0 Comments

call和callStatic方法

发布于:2012-12-27  |   作者:广州网站建设  |   已聚集:人围观

        如何防止调用不存在的方法而出错?一样的道理,使用call魔术重载方法。

call方法原型如下:


  1. mixed call ( string $name , array $arguments ) 

 

当调用一个不可访问的方法(如未定义,或者不可见)时,call()会被调用。其中$name参数是要调用的方法名称。$arguments参数是一个数组,包含着要传递给方法的参数,如下所示:
网站建设
  1. public function call($name, $arguments) {  
  2. switch(count($arguments)){  
  3. case 2:  
  4. echo $arguments[0]*$arguments[1],PHP_EOL;  
  5. break;  
  6. case 3:  
  7. echo array_sum($arguments),PHP_EOL;  
  8. break;  
  9. default:  
  10. echo '参数不对',PHP_EOL;  
  11. break;  
  12. }  
  13. }  
  14. $a->make(5);  
  15. $a->make(5,6); 

       以上代码模拟了类似其他语言中的根据参数类型进行重载。跟call方法配套的魔术方法是callStatic。当然,使用魔术方法“防止调用不存在的方法而报错”,并不是魔术方法的本意。实际上,魔术方法使方法的动态创建变为可能,这在MVC等框架设计中是很有用的语法。假设一个控制器调用了不存在的方法,那么只要定义了call魔术方法,就能友好地处理这种情况。

         试着理解代码清单1-3所示代码。这段代码通过使用callStatic这一魔术方法进行方法的动态创建和延迟绑定,实现一个简单的ORM模型。

代码清单1-3 simpleOrm.php


  1. <?php 
  2. abstract class ActiveRecord {  
  3. protected static $table;  
  4. protected $fieldvalues;  
  5. public $select;  
  6.  
  7. static function findById($id) {  
  8. $query = "select *from " 
  9. .static::$table  
  10. ." where id=$id";  
  11. return self::createDomain($query);  
  12. }  
  13. function get($fieldname) {  
  14. return $this->fieldvalues[$fieldname];  
  15. }  
  16. static function callStatic($method, $args) {  
  17. $field = preg_replace('/^findBy(\w*)$/', '${1}', $method);  
  18. $query = "select *from " 
  19. .static::$table  
  20. ." where $field='$args[0]'";  
  21. return self::createDomain($query);  
  22. }  
  23.  
  24. private static function createDomain($query) {  
  25. $klass = get_called_class();  
  26. $domain = new $klass();  
  27. $domain->fieldvalues = array();  
  28. $domain->select = $query;  
  29. foreach($klass::$fields as $field => $type) {  
  30. $domain->fieldvalues[$field] = 'TODO: set from sql result';  
  31. }  
  32. return $domain;  
  33. }  
  34.  
  35. }  
  36. class Customer extends ActiveRecord {  
  37. protected static $table = 'custdb';  
  38. protected static $fields = array(  
  39.  
  40. 'id' => 'int',  
  41. 'email' => 'varchar',  
  42. 'lastname' => 'varchar'  
  43. );  
  44. }  
  45. class Sales extends ActiveRecord {  
  46. protected static $table = 'salesdb';  
  47. protected static $fields = array(  
  48. 'id' => 'int',  
  49. 'item' => 'varchar',  
  50. 'qty' => 'int'  
  51. );  
  52. }  
  53.  
  54. assert ("select *from custdb where id=123" ==  
  55. Customer::findById(123)->select);  
  56. assert ("TODO: set from sql result" ==  
  57. Customer::findById(123)->email);  
  58. assert ("select *from salesdb where id=321" ==  
  59. Sales::findById(321)->select);  
  60. assert ("select *from custdb where Lastname='Denoncourt'" ==  
  61. Customer::findByLastname('Denoncourt')->select); 

 

再举个类似的例子。PHP里有很多字符串函数,假如要先过滤字符串首尾的空格,再求出字符串的长度,一般会这么写:

  1. strlen(trim($str)); 

 

如果要实现JS里的链式操作,比如像下面这样,应该怎么实现?

  1. $str->trim()->strlen() 

 

很简单,先实现一个String类,对这个类的对象调用方法进行处理时,触发call魔术方法,接着执行call_user_func即可。
飞机