魔术方法 Magic methods
__construct
__destrurct
__call
__callStatic
__get
__set
__isset
__unset
__sleep
__wakeup
__toString
__invoke
__set_state
__clone
__debugInfo
Caution: PHP将所有以(两个下划线)开头的类方法保留为魔术方法。所以在定义方法时,除了上述魔术方法,建议不要使用前缀**
构造方法 __construct()
具有构造函数的类会在每次创建新对象时调用此方法,所以适合在对象调用时做一些初始化工作。
Note: 如果子类中定义了构造函数则不会隐式调用其父类的构造函数。需要在子类的构造函数中调用parent::__construct()。如果子类没有定义构造函数,则会如普通的类方法一样从父类继承(父类方法没有被定义为private)。
析构方法 __destruct(void)
析构方法会在某个对象的所有引用都被删除,或当前对象被显式销毁时执行。
析构函数即使在使用exit()终止脚本运行时也会被调用。在析构函数中调用exit()将会终止其余关闭操作的运行。
析构方法必须时public修饰。这个方法将会自动在外部调用,设置为protected、private将导致警告。
PHP手册
方法重载
call(string $name, array $arguments)、callStatic(string $name, array $arguments)
$name参数是要调用的方法名。$arguments参数是一个枚举数组,包含要传递给方法$name的参数。
案例:
class MethodTest {
public function __call($name, $arguments) {
echo "Calling object method '$name' " . implode(',',$arguments) . "\n";
}
public static function __callStatic($name, $arguments) {
echo "Calling object method '$name' " . implode(',',$arguments) . "\n";
}
}
$obj = new MethodTest();
$obj->runTest('in object context');
MethodTest::runTest('in static context');
属性重载
public void __set(string $name, mixed $value)
在给不可访问的属性赋值时,set()会调用
`public mixed get(string $name)
public bool isset(string $name)`
读取不可访问的属性时,__get()会调用
当对不可访问的属性调用isset()或者empty()时,isset()会被调用public void __unset(string $name)
当对不可访问属性调用unset()时,__unset()会被调用
class ProperTest {
// 被重载的数据保存在此
private $data = [];
public $declared = 1;
private $hidden = 2;
public function __set($name, $value) {
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
public function __get($name) {
echo "Getting '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Undefined property via __get():' . $name .
'in' . $trace[0]['file'] .
'on line' . $trace[0]['line'],
E_USER_NOTICE
);
return null;
}
public function __isset($name) {
echo "Is '$name' \n";
unset($this->data[$name]);
}
// 非魔术方法
public function getHidden() {
return $this->hidden;
}
}
echo "\n";
$obj = new ProperTest();
$obj->a = 1; // Setting 'a' to '1'
echo $obj->a . "\n\n"; // Getting 'a' 1
var_dump(isset($obj->a)); // Is 'a'
unset($obj->a);
var_dump(isset($obj->a)); // Is 'a'
echo "\n";
echo $obj->declared . "\n\n"; // 1
echo "Let's experiment with the private property named 'Hidden':\n";
echo "Privates are visable inside the class, so __get() not used... \n";
echo $obj->getHidden() . "\n";
echo "Privates not visible outside of class, so __get() is used... \n";
echo $obj->hidden . "\n";
sleep() 和 wakeup()
public array __sleeep(void)
serialize()函数会检查类中是否存在一个魔术方法sleep()。如果存在,则调用,然后再执行序列化。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。
`void wakeup(void)`
Note: __sleep()不能返回父类的私有成员的名字。这样会产生一个E_NOTICE级别的错误。
sleep()方法常用于提交未提交的数据,或类似的清理操作。同时,如果一些很大的对象,但不需要全部保存,这个功能很好用。
与之相反,unserialize()会检查是否存在一个wakeup()方法。如果存在,则会先调用wakeup()方法,预先准备对象需要的资源。
wakeup()经常用在反序列化操作中,例如重新建立数据库连接,或者执行其他初始化操作。
__toString()
用于一个类被当成字符串应该怎样回应。例如:echo $obj;应该显示什么。此方法必须返回一个字符串。否则将发出一个致命的错误。
class TestClass {
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class;
__invoke()
mixed __invoke([$...])
当尝试以调用函数的方式调用一个对象时,__invoke()方法会被自定调用
class CallableClass {
public function __invoke($param1, $param2) {
echo $param1 . " " . $param2 . "\n";
}
}
$obj = new CallableClass();
$obj(123, 456);
var_dump(is_callable($obj));
__set_state()
static object __set_state(array $properties)
调用var_export()导出类时,此静态方法会被调用。本方法的唯一参数是一个数组,其中包含array('property'=>value,...)
class A {
public $var1;
public $var2;
public static function __set_state($an_array) {
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A();
$a->var1 = 5;
$a->var2 = 'foo';
eval('$b = '.var_export($a, true) . ';');
echo $b->var2;
__debugInfo()
array __debugInfo(void)
调用var_dump()导出对象属性是,此方法会被调用。如果未在对象上定义该方法,则将显示所有public, protected, private属性。
__clone()
void __clone(void)
当复制完成时,如果定义了clone()方法,则新创建的对象(复制生成的对象)中的clone()方法会被调用,可用于修改属性的值。