PHP把所有以__(两个下划线)开头的类方法当成魔术方法。
所以当自定义类方法时,除了魔术方法,建议不要以 __为前缀。 php魔术方法包括: __construct(), __destruct(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __clone(),__call()等。
-
__construct() 是php中类的构造方法,用来初始化类中的属性。同一个类中只能声明一个构造方法,故不能重载。但可以使用默认参数。构造方法一般是public类型的,如果是private类型,就会构成单例模式,php单例设计模式。
<?php class Person { private $name; private $age; private $email; //声明类的构造函数 public function __construct($name="yeetrack", $age=1, $email="yeetrack@123.com") { $this->name = $name; $this->age = $age; $this ->email = $email; } public function printInfo() { echo "name->" . $this->name . " age->" . $this->age . " email->" . $this->email . "<br/>"; } } $per = new Person("youthflies",2); $per->printInfo(); ?>
-
__destruct()是php中类的析构方法,对象在销毁前自动调用此方法,常在析构方法中执行关闭文件,释放连接等操作。php自带垃圾回收机制,当对象不能被访问时就会自动启用垃圾回收的机制,释放对象占用的堆空间。而php的析构方法是在启动垃圾回收之前调用的方法。析构方法方法只有需要的时候才需要声明。
-
为了封装和数据保护,我们一般把类的数据属性声明为private,如果需要频繁的读取数据属性,就会很繁琐。__set()方法来解决这个问题,它能在程序运行时为private类型的数据赋值。承接上面代码:
//声明魔术方法__set() public function __set($propertyName, $value) { if($propertyName == "name") $this->name = $value; //为name赋值 elseif ($propertyName == "age") { if($value>200 | $value<0) //判断age范围 return; $this->age = $value; } elseif ($propertyName == "email") $this->email = $value; }
有了__set的声明我们就可以这样为成员属性赋值(虽然属性是private类型的)
$per = new Person("youthflies",2); $per->name = "youthflies"; $per ->age = 12; $per->email = "youthflies@123.com"; $per->printInfo();
这样赋值,php就会默认去调用__set()方法。
-
如果一个属性被声明为private类型,而在对象外面直接获取该属性,php就会默认去寻找__get()方法。该方法可以在程序运行中获取private类型的数据。承接上面代码:
//声明魔术方法__get() public function __get($propertyName) { if($propertyName == "name") return $this->name; elseif ($propertyName == "age") //不允许获取age属性 return "secret"; elseif ($propertyName == "email") return $this->email; }
如上面代码,我们可以在__get()方法中加入一些权限控制,或者返回一些假数据等等。
-
isset()方法用来判断变量是否存在。如果类中的属性为public,我们可以直接用isset()方法来判断对象中的属性,但如果为private类型的,就不能直接判断了,需要用到__isset()方法。只有在类内部声明了__isset()方法,我们才可以在类外部用isset()来间接判断类中的private数据。承接上面代码:
//声明魔术方法__isset() public function __isset($propertyName) { if($propertyName == "name") return isset($this->name); elseif ($propertyName == "age")//不允许判断age属性 return false; elseif ($propertyName == "email") return isset($this->email); }
经过上面的声明,我们就可以在类外这样:
var_dump(isset($per->name)); var_dump(isset($per->age)); var_dump(isset($per->email));
-
unset()方法用来删除变量,如果类中的属性是public,我们可以直接用unset()删除,如果为private,就要通过__unset()方法了,类似于__isset()方法。
//声明魔法方法__unset()方法 public function __unset($propertyName) { if($propertyName == "name")//不允许删除name属性 return; elseif($propertyName == "age") unset($this->age); elseif ($propertyName == "email") unset($this->email); }
这样我们就可以在类外面直接unset()类中private类型的属性了。
-
__toString()用来获取对象的字符串输出,当我们直接打印某对象引用 时,该方法被自动调用。 如下代码:
//声明魔法方法__toString() public function __toString() { return "name: " . $this->name . "<br/>age: " . $this->age . "<br/>email: " . $this->email . "<br/>"; }
这样我们可以在外面直接 echo $per; php会默认去调用类中的__toString()方法。
-
当我们调用的方法,在类中不存在时,就会出现error,程序会shutdown。__call()方法用来解决这种情况,当调用了类中不存在的方法时,__call()方法就会被调用。该方法有两个参数,一是不存在的方法的名称,二是不存在的方法的参数(以数组的形式保存)。
//声明魔法方法__call() public function __call($methodName, $args) { echo "方法:" . $methodName . "不存在<br/>"; print_r($args); }
-
__autoload()方法用于自动加载需要的类文件。 我们一把为每个类都单独建立一个php文件,当需要这个类时,就用include将php文件包含进来。 如果类文件非常多,就很麻烦。__autoload()可以自动加载,当然前提是我们用一定规则命名类文件。
//声明魔法方法__autoload() public function __autoload($className) { include(strtolower($className) . ".class.php"; } $hello = new Hello();
如上代码,我们新建Hello对象,如果Hello类不存在,就会默认调用autoload()方法,$className获得参数"Hello",然后它去include当前文件夹下的Hello.class.php文件,如果我们按照这种方式命名我们的php文件,就会include成功。
-
php5通过引用来调用对象,如果有建立一个独立副本的需求,可以通过clone方法,clone获得的时两个完全一样且互相独立的对象。如果想在clone过程中进行一些自定义的初始化操作,可以在类中声明__clone()方法,在调用clone()方法时,php会默认调用__clone()方法。
//声明魔法方法__clone() public function __clone() { $this->name = "youthflies__clone"; $this->age = "12__clone"; $this->email = "youthflies@124.com__clone"; }
声明后, 利用下面两行代码查看效果。
$per2 = clone $per; $per2->printInfo();
-
__sleep()方法在将对象串行化时(即调用serialize()函数时)会被调用,关于串行化,参考php对象串行化 。__sleep()方法没有参数,返回值是一个数组,用来指定要被串行化的属性。
//声明魔法方法__sleep() public function __sleep() { return array("name","email"); }
这样在串行化$per时,就只会把name和email两个属性串行化。
-
__wakeup()方法用来在反串行化对象时,给将要生成的对象初始化一些数据。
//声明魔法方法__wakeup() public function __wakeup() { $this->age = 12; }
由于我们在声明__sleep()时,没有串行化age属性,所以我们在__wakeup()方法中,手动为age属性赋值,这样当反串行化时,age就会被赋值为12.
近期评论