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
访问未声明过的属性(此时在类中声明的魔术方法会被调用)
重载对于private
或protected
属性不起作用,对于已经在类中声明过的public
属性也不起作用。
对于在类中声明过的private
或protected
属性,如果通过类的实例对象访问同名属性,相当于重新创建了一个属性。
通过代码验证:
// 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(); // 没有打印输出 魔术方法没有调用
访问private
和protected
属性:
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
方法重载
在对象中调用一个不可访问方法(包括未在类中声明的方法,private
和protected
方法)时, __call(string $name, array $arguments)
会被调用。
如果通过实例对象调用了在类中声明过的同名的private
或protected
方法,那么相当于新建了一个同名的方法调用,跟原来的private
或protected
方法没有关系,原来的private
或protected
方法也不受影响。
在静态上下文中调用一个不可访问方法时,__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
的参数。