一、前言
特别注意,虽然__call()或__callStatic()方法就是为实现重载而设计的,但是为了便于理解,先将两者分开进行理解!!!
__call()方法的特性是它的特性,用其实现重载是实现重载,这是两码事~
二、__call()方法
在PHP5.3.0之后,又增加了一个__callStatic()方法。它们都是PHP中的魔术方法,所谓魔术方法,就是系统在特定时刻自动调用的方法!除了它们俩,PHP中还有其它一些魔术方法(见手册)。对于魔术方法,个人理解是,各魔术方法有一个共同点:系统自动调用,有两个不同点:调用的时间、调用之后产生的作用
对于__call()和__callStatic()的调用时间和功能(通俗点就是调用之后产生的结果),举个栗子(代码如下)
<?php class A { public function test () { static::who(); A::who(); self::who(); $this->who(); } /** *私有方法 */ private function test2(){ } public static function __callStatic($a, $b) { var_dump(‘A static‘); } public function __call($a, $b) { var_dump(‘A call‘); } } $a = new A; $a->test(); A::test1(); $a->test2(); ?>
输出为
通过这个栗子,不难看出两点
·在类内部调用本类当中的一个不可访问(如果是本类中,那就只能是不存在才不可访问,如果是在本类外不可访问还可能是没有访问权限)的方法时,不管是对象方式,还是静态方式,都只能触发__call()方法
·在类外部调用一个类中的一个不可访问的方法时,对象方式就触发__call()方法,静态方式就触发__callStatic()方法
ps,不可访问不仅仅代表不存在
1、再举个栗子
class MethodTest { public function __call($name,$arguments) { // 注意: $name 的值区分大小写 echo "Calling object method ‘$name‘的参数有多个,分别是:".implode (‘、‘,$arguments)."<br/>" ; } /** PHP 5.3.0之后版本 */ public static function __callStatic($name,$arguments) { // 注意: $name 的值区分大小写 echo "Calling static method‘$name‘的参数有多个,分别是:".implode (‘、‘,$arguments)."<br/>" ; } } $obj=new MethodTest ; $obj->runTest (‘in object context‘,‘另外一个参数‘); MethodTest::runTest (‘in static context‘,‘另外一个参数‘); // PHP 5.3.0之后版本
输出为
通过这个栗子,也不难看出两点
·触发__call()或__callStatic()方法时,系统会自动将所调用的那个不可访问的方法的方法名作为第一个参数传入__call()或__callStatic()方法中,而将所调用的不存在的方法传入的参数,作为第二个参数(而且是封装成了一个数组,即每一个元素就是调用不可访问方法时传入的一个参数)传入__call()或__callStatic()方法中
·那么在__call或__callStatic()方法内部,就可以根据所传入的两个参数做一些操作,这就可以与重载挂上勾了!
2、额。。。最后举个栗子
class Foo{ public function __call($name,$arguments){ print("你是想调用$name"."()方法吗? 额...不好意思呦,该方法不可访问!<br/>"); } } $foo=new Foo; $foo->doStuff(); $foo->doStuff1();
输出为
二、重载
<?php /** *------------------------------------------------------------- *正是鉴于__call()或__callStatic()方法的这种特性,即所传入的$name和$arguments,它们就用来实现重载!这点与JS每一个普通方法中都可以获取到一个arguments数组其实异曲同工 *举个例子 */ class Foo1{ public function __call($name,$arguments){ if($name=="doStuff"){ /** *实际上,不仅仅可以第一个参数类型,还可以判断参数个数,以及参数顺序,那么就和C++等强数据类型语言的重载效果是一样的了! */ if(is_int($arguments[0])){ $this->doStuffForInt($arguments[0]); }else if(is_string($arguments[0])){ $this->doStuffForString($arguments[0]); } } } private function doStuffForInt($a){ echo "执行的是doStuffForInt()方法"; } private function doStuffForString($a){ echo "执行的是doStuffForString()方法"; } } $foo1=new Foo1; $foo1->doStuff(‘1‘);
结果:执行的是doStuffForString()方法