[学习]php 重载

php 重载

官方手册上的评论里不推荐在生产环境使用重载:不利于多人协作,代码可维护性变差,容易导致不可预料的错误等。

重载分为属性重载和方法重载。

重载的作用是动态的创建类属性和方法,通过php内置的专用的魔术方法实现。

属性重载用到的魔术方法:

  • public __set(string $name, mixed $value):void
  • public __get(string $name):mixed
  • public __isset(string $name):bool
  • public __unset(string $name):void

方法重载用到的魔术方法:

  • public __call(string $name, array $arguments):mixed
  • public static __callStatic(string $name, array $arguments):mixed

属性重载

属性发生重载的情形:

  • 通过类实例化的对象访问未在类中声明的属性(此时在类中声明的魔术方法会被调用)
  • 在类的内部通过$this访问未声明过的属性(此时在类中声明的魔术方法会被调用)

重载对于privateprotected属性不起作用,对于已经在类中声明过的public属性也不起作用。

对于在类中声明过的privateprotected属性,如果通过类的实例对象访问同名属性,相当于重新创建了一个属性。

通过代码验证:

// php 版本5.6.9
class Test {
    private $data = array();
    public $name = "test";
    private $age = 12;
    protected $height = 180;

    // 魔术方法
    public function __set($key,$val) {
        echo "set {$key} to {$val}. \n";
        $this->data[$key] = $val;
    }

    public function __get($key) {
        echo "Get {$key}. \n";
        if(array_key_exists($key,$this->data)) {
            return $this->data[$key];
        }
        return null;
    }

    public function __isset($key) {
        echo "Check {$key} is set. \n";
        return isset($this->data[$key]);
    }

    public function __unset($key) {
        echo "Unset {$key}. \n";
        unset($this->data[$key]);
    } 

    function getAge() {
        return $this->age;
    }
    function getHeight() {
        return $this->height;
    }
    function getQ() {
        return $this->q;
    }
    function getName() {
        return $this->name;
    }
}

$t = new Test();

通过实例对象/$this访问未声明的属性:

$t->getQ(); // Get q.
$t->q; // Get q.
$t->q = 123; // set q to 123.
echo $t->getQ()."\n"; // Get q.  123

访问已声明过的public属性:

$t->name; // 没有打印输出 魔术方法没有调用
$t->getName(); // 没有打印输出 魔术方法没有调用

访问privateprotected属性:

echo $t->getAge()."\n"; // 12 魔术方法没有调用 
echo $t->getHeight()."\n"; // 180 魔术方法没有调用
$t->age = 123; // set age to 123.
$t->height = 456; // set height to 456.
echo $t->getAge()."\n"; // 12 魔术方法没有调用 虽然通过$this访问,但取的值不是123
echo $t->getHeight()."\n"; // 180 魔术方法没有调用 虽然通过$this访问,但取的值不是456

方法重载

在对象中调用一个不可访问方法(包括未在类中声明的方法,privateprotected方法)时, __call(string $name, array $arguments) 会被调用。
如果通过实例对象调用了在类中声明过的同名的privateprotected方法,那么相当于新建了一个同名的方法调用,跟原来的privateprotected方法没有关系,原来的privateprotected方法也不受影响。

在静态上下文中调用一个不可访问方法时,__callStatic(string $name, array $arguments) 会被调用。

这里的静态上下文有多种情形:

// php 版本5.6.9
class MethodTest 
{
    public function __call($name, $arguments) 
    {
        // 注意: $name 的值区分大小写
        echo "Calling object method ‘$name‘ "
             . implode(‘, ‘, $arguments). "\n";
    }

    public static function __callStatic($name, $arguments) 
    {
        // 注意: $name 的值区分大小写
        echo "Calling static method ‘$name‘ "
             . implode(‘, ‘, $arguments). "\n";
    }
    private function t() {
        echo "t function call. \n";
    }
    protected function tt() {
        echo "tt function call. \n";
    }
    static function ttt() {
        echo "ttt function call. \n";
    }

    function aaa() {
        MethodTest::tee();
    }
    static function bbb() {
        static::tee();
        self::tee();
    }
}

$obj = new MethodTest;

情形一:

$obj->runTest(‘in object context‘);

MethodTest::runTest(‘in static context‘); // 直接通过类名加双冒号调

情形二:

MethodTest::aaa(); // 情形二本质上还是情形一

情形三:

$obj->bbb(); // 在静态方法中

$name 参数是要调用的方法名称。$arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。

[学习]php 重载

上一篇:jQuery


下一篇:Microsoft NLayerApp案例理论与实践【分布式服务】