2011-02-18 79 views
1

我写了一个相当简单的延迟加载代理类,这是我在过去超过在http://blog.simonholywell.com/post/2072272471/logging-global-php-objects-lazy-loading-proxy通过引用传递__call()参数失败。任何工作?

记录现在,当我转换的另一个项目,它的工作我已经被进行代理的方法,它有一个绊倒的参数通过引用传递给它。当这个经过我的代理类的__call方法获得:

Fatal error: Method LazyLoader::__call() cannot take arguments by reference in /home/simon/file/name.php

这如何可能得到解决或周围工作的任何巧妙的构思。如果可能,最好不要重构需要通过引用的代码。

延迟加载代理类看起来是这样,但在my blog post的描述能够更好地解释了目的:

<?php 
/** 
* @author Simon Holywell <[email protected]> 
*/ 
class LazyLoadingProxy { 
    /** 
    * Where the instance of the actual class is stored. 
    * @var $instance object 
    */ 
    private $instance = null; 

    /** 
    * The name of the class to load 
    * @var $class_name string 
    */ 
    private $class_name = null; 

    /** 
    * The path to the class to load 
    * @var $class_path string 
    */ 
    private $class_path = null; 

    /** 
    * Set the name of the class this LazyLoader should proxy 
    * at the time of instantiation 
    * @param $class_name string 
    */ 
    public function __construct($class_name, $class_path = null) { 
     $this->setClassName($class_name); 
     $this->setClassPath($class_path); 
    } 

    public function setClassName($class_name) { 
     if(null !== $class_name) { 
      $this->class_name = $class_name; 
     } 
    } 

    public function getClassName() { 
     return $this->class_name; 
    } 

    public function setClassPath($class_path) { 
     if(null !== $class_path) { 
      $this->class_path = $class_path; 
     } 
    } 

    public function getClassPath() { 
     return $this->class_path; 
    } 

    /** 
    * Get the instance of the class this LazyLoader is proxying. 
    * If the instance does not already exist then it is initialised. 
    * @return object An instance of the class this LazyLoader is proxying 
    */ 
    public function getInstance() { 
     if(null === $this->instance) { 
      $this->instance = $this->initInstance(); 
     } 
     return $this->instance; 
    } 

    /** 
    * Load an instance of the class that is being proxied. 
    * @return object An instance of the class this LazyLoader is proxying 
    */ 
    private function initInstance() { 
     Logger::log('Loaded: ' . $class_name); 
     require_once($this->class_path); 
     $class_name = $this->class_name; 
     return new $class_name(); 
    } 

    /** 
    * Magic Method to call functions on the class that is being proxied. 
    * @return mixed Whatever the requested method would normally return 
    */ 
    public function __call($name, &$arguments) { 
     $instance = $this->getInstance(); 
     Logger::log('Called: ' . $this->class_name . '->' . $name . '(' . print_r($arguments, true) . ');'); 
     return call_user_func_array(
       array($instance, $name), 
       $arguments 
      ); 
    } 

    /** 
    * These are the standard PHP Magic Methods to access 
    * the class properties of the class that is being proxied. 
    */ 
    public function __get($name) { 
     Logger::log('Getting property: ' . $this->class_name . '->' . $name); 
     return $this->getInstance()->$name; 
    } 

    public function __set($name, $value) { 
     Logger::log('Setting property: ' . $this->class_name . '->' . $name); 
     $this->getInstance()->$name = $value; 
    } 

    public function __isset($name) { 
     Logger::log('Checking isset for property: ' . $this->class_name . '->' . $name); 
     return isset($this->getInstance()->$name); 
    } 

    public function __unset($name) { 
     Logger::log('Unsetting property: ' . $this->class_name . '->' . $name); 
     unset($this->getInstance()->$name); 
    } 
} 

任何帮助极大的赞赏。

+0

我不认为它是可能的。 – 2011-02-18 16:10:01

+0

是的,我认为你可能是对的。仍然希望有人可能有魔法修复,但! :) – Treffynnon 2011-02-18 16:11:39

回答

4

简短的答案是不通过参考。在99.9%的情况下,你不需要它。而在其他0.1%的情况下,你可以解决缺乏参考的问题。请记住,objects are passed by object-reference anyway因此您不需要为它们使用变量引用。

现在,就解决方法而言,我亲自将其硬编码到适配器中。因此,扩展你的特定类的代理,并包含一个特定方法的包装器。然后实例化该新的扩展类,而不是该类的核心代理。它脏吗?绝对。但是,这是您唯一的解决方法,不需要重构原始类,不要通过引用来引用参数,或者重构调用方以防止通过引用传递(反正不推荐)。

1

这是一个技巧给你,通过引用通过__call魔法方法传递变量: 我现在不会多久会这样工作或巫婆PHP版本。 我在php 5.3.2上测试过

Fitst在__call函数定义中不能通过$ reference传递$ arguments变量。因为PHP下跌的错误。

所以第一: 下面是一个代码什么没有做,你想引用的论据是什么,但几乎好;)

class A { public $x = array(); } 

    class Teszt{ 
     private function addElement(&$list){ 
      $list->x[] = 'new element'; 
      return count($list->x); 
     } 

     public function __call($name,$arguments){ 
      if (!preg_match('#^add([0-9]+)Element$#', $name, $matches) || $matches[1]<1){ 
       trigger_error ("Function is not exists teszt::$name", E_USER_ERROR); 
      }     
      $ret = null; 
      for($i=0;$i<$matches[1];$i++){ 
       $ret = call_user_func_array(array($this,'addElement'), $arguments); 
      } 
      return $ret; 
     } 
    } 

    $a = new A(); 
    $a->x = array('old element','old element'); 
    $t = new Teszt(); 
    $cnt = $t->add5Element($a); 
    var_dump($a); 
    var_dump($cnt); 

OUTPUT:

PHP Warning: Parameter 1 to Teszt::addElement() expected to be a reference, value given in /home/gkovacs/callMagicWithReference.php on line 19 
    PHP Stack trace: 
    PHP 1. {main}() /home/gkovacs/callMagicWithReference.php:0 
    PHP 2. Teszt->add2Element() /home/gkovacs/callMagicWithReference.php:27 
    PHP 3. Teszt->__call() /home/gkovacs/callMagicWithReference.php:0 
    PHP 4. call_user_func_array() /home/gkovacs/callMagicWithReference.php:19 
    PHP Warning: Parameter 1 to Teszt::addElement() expected to be a reference, value given in /home/gkovacs/callMagicWithReference.php on line 19 
    PHP Stack trace: 
    PHP 1. {main}() /home/gkovacs/callMagicWithReference.php:0 
    PHP 2. Teszt->add2Element() /home/gkovacs/callMagicWithReference.php:27 
    PHP 3. Teszt->__call() /home/gkovacs/callMagicWithReference.php:0 
    PHP 4. call_user_func_array() /home/gkovacs/callMagicWithReference.php:19 
    object(A)#1 (1) { 
     ["x"]=> 
     array(2) { 
     [0]=> 
     string(11) "old element" 
     [1]=> 
     string(11) "old element" 
     } 
    } 
    NULL 

哦~~:((( 利特尔 'HACK' 之后:

​​

输出:

object(A)#1 (1) { 
    ["x"]=> 
    array(4) { 
    [0]=> 
    string(11) "old element" 
    [1]=> 
    string(11) "old element" 
    [2]=> 
    string(11) "new element" 
    [3]=> 
    string(11) "new element" 
    } 
} 
int(4) 

正如我们想要的。这只适用于对象,但不适用于数组-s。 没有与阵列的一种方法,可以在调用的时候,传递通过引用... 是这样的:(和科西嘉的,你可以用这样的方式与对象太)

$cnt = $t->add5Element(&$a); 

在这种情况下PHP生成通知...

如果可能,重新定义函数的最简单方法。我的代码中有: :private functionaddElement($ list),请不要在参数列表中定义为引用。而且,当您在之前的消息中阅读时,它会起作用,因为对象会自动通过引用传递。 但是有时,由于已实现的接口或其他原因,您无法重新定义函数...

0

它可以。所以饿了。

<?php 
     class MyClass(){ 
      public function __call($name, $params) 
      { 
      var_dump($params); 
      $params[0][0] = '222'; 
      } 
     } 
     $obj = new MyClass();  
     $info = 3; 

     var_dump($info); 
     $obj->setter([&$info]); 
     var_dump($info);