【类】变量复用,函数复用

变量复用

变量复用,适用于以下场景:1,整个项目公用的部分(比如errors);2,一组类要通信,或者同一个类的两个函数之间要通信,通信数据可以用类来定义和约束;

场景1

所有错误相关的部分要放在一个类里面,方便查找和使用;

<?php
class errors
{
    const ERROR_PARAMS = 'params error';
    const ERROR_EMPTY_PARAM = 'empty param';
}

class TestModel
{
    public function run()
    {   
        $error = errors::ERROR_PARAMS;
        var_dump($error);
        return $error;
    }   
}

$model = new TestModel();
$model->run();

解释,errors是整个项目都可以访问的,可以添加更多的错误消息在里面。

 

场景2:

同一个类的两个函数中间需要通信,我们需要对这种通信定义一下数据结构。

<?php
class DataMeta
{
    public $mobile = '';
    public $message = '';
}

class Sms
{
    public function send($mobile, $message)
    {   
        $data = new DataMeta();
        $data->mobile = $mobile;
        $data->message = $message;

        if ($this->checkValid($data)) {
            echo "Allow to send\n";
        } else {
            echo "Not allowed to send\n";
        }   
    }   

    public function checkValid(DataMeta $data)
    {   
        if ($data->mobile && $data->message) {
            return true;
        } else {
            return false;
        }
    }
}

$model = new Sms();
$model->send(0, '');
$model->send(12345678910, 'my test');

checkValid函数对参数进行了校验,我们使用了一个用于通信的数据类型DataMeta,里面包含了我们所需要的结构化数据。显示定义DataMeta,是为了更好地理解。

当然使用DataMeta这个类型是有些弊端的,如果这个数据结构有很大的变动(比如字段名相同,但实际的含义已经变化了),那么用数组和注释可能比DataMeta这样的约束要更好一些。

总结下:

情况1,有一组数据,需要在函数间传递,并且结构不会有变化的;办法是:可以定义一个MetaClass来约束这组数据。

情况2,有一组数据,需要在函数间传递,但是结构会经常性变化,则不能使用MetaClass来约束;办法是:用数组和注释来说明;特别地,Stdclass也适合这个场景;

情况3,有一组数据,需要在函数间传递,结构上只会新增字段,原始字段含义保持;办法是:依然可以用MetaClass来约束。

 

以上解释了PHP之间传递某个有结构约束的变量,可以有的方法。

除此之外,我们希望关心,有些类是完成类似的功能,也遵循一些共同的动作,这些类的函数名是一致的。

 

函数约束

函数约束的解决方案:1,基类派生类;2,接口interface。

如何区分哪种场景下使用基类派生类,哪种场景下使用interface。

我个人看法是:

1,如果能用接口实现最好优先使用接口,继承尽量不要使用;

2,接口只定义约束,并不包含实现,所以各个类动作很不相同,只用接口来约束需要实现的函数即可(大多数的业务代码就是很不同,用接口比较ok);

3,如果基类已经有完整的功能,派生类需要自己个性化完成的动作并不太多,使用基类继承类。

代码片段1:

实现interface时,未实现interface的函数,会报错。所以使用interface时,定义的函数是必须实现的。

<?php
interface SmsInterface
{
    public function sendSms($abc);
}

class m1 implements SmsInterface
{
    public function sendSms($aaa = 'cc')
    {
        var_dump(__CLASS__);
    }
}

class m2 implements SmsInterface
{
    public function __construct()
    {
        var_dump(__CLASS__);
    }
}

$a = new m1();
$a->sendSms();
$b = new m2();

执行时,报错:Fatal error: Class m2 contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (SmsInterface::sendSms) in

 

代码片段2:

interface定义的函数不携带参数。

<?php 
interface SmsInterface
{   
    public function sendSms();
}       
    
class m1 implements SmsInterface
{
    public function sendSms()
    {
        var_dump(__CLASS__);
    }
}       
    
class m2 implements SmsInterface
{   
    public function __construct()
    {
        var_dump(__CLASS__);
    }
    public function sendSms()
    {
        var_dump(__CLASS__);
    }
}

$a = new m1();
$a->sendSms();

$b = new m2();
$b->sendSms();

这段代码,没问题,可以正常执行。

 

代码片段3:

如果interface的函数是携带参数的,那么实现类必须是和interface的函数原型保持一致,也需要携带参数才可以。

<?php
interface SmsInterface
{
    public function sendSms($mobile, $message);
}

class m1 implements SmsInterface
{
    public function sendSms()
    {
        var_dump(__CLASS__);
    }
}

$a = new m1();
$a->sendSms();

执行时候报错:Fatal error: Declaration of m1::sendSms() must be compatible with SmsInterface::sendSms($mobile, $message)

代码片段4:

<?php
interface SmsInterface
{
    public function sendSms($mobile, $message);
}

class m1 implements SmsInterface
{
    public function sendSms($mobile, $message)
    {
        var_dump(__CLASS__);
    }
}

$a = new m1();
$a->sendSms(123, 'message');

这段代码没问题,可正常执行。

代码片段5:

不再详细展开,有兴趣的自己动手实践下之后的结论。

关于默认参数:

a,如果interface的函数有默认参数,实现类也必须实现自己的函数,所以interface的默认参数并不起作用;

b,实现类如果有默认参数,调用时候走默认参数逻辑没问题;

关于参数列表不一致:

如果实现类的参数列表比interface定义的要少,是会报错的;

如果实现类的参数列表比interface定义的要多,语法上不会报错,也可以使用,另外的解决方案是setField()这样的set函数;

posted on 2018-01-02 15:20  awildfish  阅读(1156)  评论(0编辑  收藏  举报

导航