如何使用PHP反射设置静态属性?

如何使用PHP反射设置静态属性?,php,phpunit,Php,Phpunit,我正在使用PHPUnit创建一个模拟类进行测试 class Item extends Object { protected static $_cache; } 我非常肯定mocking会做类似的事情(如果我错了,请纠正我): 当填充我的项的缓存时,它会检查传入的对象是否是项的实例。由于mock没有显式定义$\u缓存,因此无法检查实例类型 PHP根本没有很好地记录反射函数。有没有一种方法可以在事件发生后设置静态变量,从而使类成为 class Mock_Item_randomstring ex

我正在使用PHPUnit创建一个模拟类进行测试

class Item extends Object {
  protected static $_cache;
}
我非常肯定mocking会做类似的事情(如果我错了,请纠正我):

当填充我的
的缓存时,它会检查传入的对象是否是
的实例。由于mock没有显式定义
$\u缓存
,因此无法检查实例类型

PHP根本没有很好地记录反射函数。有没有一种方法可以在事件发生后设置静态变量,从而使类成为

class Mock_Item_randomstring extends Item {
  protected static $_cache;
}
编辑

我玩弄了很多反思方法,遇到了各种各样的问题。这是一个让我感到困惑的问题:

$mock = $this->getMock( 'Item', array( '_func' ), array(
  $argument1, $argument2
));

$mock = new ReflectionClass($mock); 


$mock->staticExpects( $this->exactly(2) )->method( '_func' );
我被认为是在抄袭全班学生。我得到这个错误:
调用未定义的方法ReflectionClass::staticExpects()

我倾向于对子类中的每类静态变量使用一种有点讨厌的技巧:

class A {
    protected static $cache;
    public static function getCache() {
        return static::$cache;
    }
    public static function setCache($val) {
        static::$cache = & $val; // note the '&'
    }
}
class B extends A {}

A::setCache('A');
B::setCache('B');
A::getCache(); // 'A'
B::getCache(); // 'B'

当然,首先最好避免使用静态变量。使用专用缓存对象,并在实例化类时将其注入。

您不必这样做
\Closure::bind
用于读取和分配私有和受保护的静态属性。请参阅

上的示例代码,我不知道这一点,但您肯定需要使用任何依赖项注入技术来避免这种情况。如果查看静态::$\u缓存没有转到项,因为它没有在模拟中显式定义,我会完全避免这种情况。该死的PHP+静态东西的局限性。我们不使用管理器对象,因此使用缓存和静态方法。使用静态变量会给您带来麻烦(您在这里所做的基本上是一个单例,您可以阅读很多关于为什么这是邪恶的),但我不明白为什么它会导致您的类型检查失败。你能把密码寄出去吗?(另外,不确定通过在子类中定义相同的变量来实现什么,但它仍然会与父类共享该变量的值。)@Tgr将对象放入缓存时,它会检查传入对象是否与获取该对象的类匹配
Mock
没有该属性,因此它将插入
缓存,而不是
Mock
缓存
Item
抛出一个异常,表示它已经得到了
Mock
来回答您最初的问题,反射不允许您定义类(您可以只使用eval,),更不用说更改已经定义的类(您需要runkit来实现这一点,事情可能会崩溃)。可以使用反射设置已经存在的类的非公共静态属性,但请参见。什么注释?:)“此页面没有用户提供的注释。”使用此选项是否会将其设置为在
Mock
中?或者它会将它设置为在
项目
中吗?我的错-我的意思是注释,但我同时测试了它,但它不起作用。使用
getProperty
/
setAccessible
/
setValue
在5.3中可以工作,但我不会打赌它将来不会崩溃(例如,相同的方法不适用于读取值)。如果您从模拟类名创建反射对象,它的工作方式就好像您在该类中一样。但是,这对您来说并不重要-因为属性仅在父类中定义,子类与父类共享它,所以在
Mock
上设置反射值具有相同的效果。(好吧,更准确地说,孩子的属性是对父母属性的引用。这就是为什么我的回答中描述的技巧有效。不过,你不能通过函数调用来做同样的事情。)我一整天都在尝试这样做,但都被淹没了。看来我周一就能解决了。我会通知你的。同时感谢您的全面回复。我暂时不会使用5.4。有趣的是,它没有在绑定页面上提到它只是5.4版本,只是结尾:如果5.4+解决了你的问题,而唯一的解决方案是重新设计你的类,为什么不尽快推出5.4版本呢?因为在我们拥有的许多站点和服务器上,很可能会有很多扩展兼容性问题
class A {
    protected static $cache;
    public static function getCache() {
        return static::$cache;
    }
    public static function setCache($val) {
        static::$cache = & $val; // note the '&'
    }
}
class B extends A {}

A::setCache('A');
B::setCache('B');
A::getCache(); // 'A'
B::getCache(); // 'B'