1.认识 __set (在给不可访问属性赋值时,__set() 会被调用)
也就是说你再访问一个类里面没有的属性,会出发这个方法
class A{ private $aa = '11'; public function __set($name, $value) { $this->$name = $value; } } $a = new A(); $a->name = 'name'; echo $a->name;
2.认识 __set (在对象中调用一个不可访问方法时,__call() 会被调用。)
class B{ private $bb = '22';
public function __call($name, $arguments) { echo $name; var_dump($arguments); } } $b = new B(); $b->names();
3.动态添加方法
class B{ private $bb = '22'; public function __set($name, $value) { $this->$name = $value; } public function __call($name, $arguments) {//注意:没用形参$name return call_user_func($this->$name,$arguments);//通过这个把属性的匿名方法加进来 注意:$arguments 是一个数组 } } $b = new B(); $b->names = function(){echo 'this is a fun ';}; $b->names(); //这时候B类里面已经有一个 属性name 指向一个匿名方法 //怎么运行呢? $b->name() 错误因为类里面没有这个方法 ---这个错误可以触发__call()魔术方法 //这时候还不能在 匿名函数 中用B类里面的 属性
4.动态加方法之,让闭包函数也能操作类里面的属性 参考(http://php.net/manual/zh/closure.bindto.php)
class C{ private $cc = '33'; public function __set($name, $value) { //$this->$name = $value; //(和上面例子比较 就改动了这个) $this->$name = $value->bindTo($this,$this);//复制当前闭包函数,绑定指定的$this作用域对象,这样匿名函数就可以访问类的属性值了 } public function __call($name, $arguments) { return call_user_func($this->$name,$arguments); } } $c = new C(); $c->username = function ($strs){ var_dump($strs);//这里其实是 call_user_func的$arguments传过来的是数组 $this->cc=4;//可以操作作用于的属性值 return '111'; }; echo $c->username('字符串');
一个完整的例子:
/** * 给类动态添加新方法 * * @author fantasy */ trait DynamicTrait { /** * 自动调用类中存在的方法 */ public function __call($name, $args) { if(is_callable($this->$name)){ return call_user_func($this->$name, $args); }else{ throw new \RuntimeException("Method {$name} does not exist"); } } /** * 添加方法 */ public function __set($name, $value) { $this->$name = is_callable($value)? $value->bindTo($this, $this): $value; } } /** * 只带属性不带方法动物类 * * @author fantasy */ class Animal { use DynamicTrait; private $dog = '汪汪队'; } $animal = new Animal; // 往动物类实例中添加一个方法获取实例的私有属性$dog $animal->getdog = function() { return $this->dog; }; echo $animal->getdog();//输出 汪汪队
动态给类里面加方法,就是把一个闭包函数通过__set和__call结合call_user_func()等方法,加入进去,
为了让匿名函数或闭包函数可以访问类的属性值,需要结合Closure类的Closure::bindTo (复制当前包对象,绑定到指定this作用域)
参考:http://www.cnblogs.com/fps2tao/p/8727248.html