【问题标题】:Static variable assignment in descendent bubbles up to parent?后代中的静态变量分配冒泡到父级?
【发布时间】:2012-11-19 11:35:58
【问题描述】:

我遇到了一个问题,我不确定这只是正常行为还是我写错了什么。我的基类中有一个方法,它通过为该特定类的所有新实例创建代理来将全局过滤器应用于给定类。我打算这样做的方式如下:

  1. static $global_filter(代理)附加到我要过滤的类,它扩展了基类object
  2. 通过我的加载机制,在新实例化时返回代理而不是实际类(这将屏蔽方法调用并相应地应用过滤器)

但是,我陷入了第 1 步,似乎当我尝试将 static $global_filter 分配给我想要过滤的后代类时,我的基类 object 也得到了相同的分配,这会破坏从它延伸出来的所有其他东西。

相关代码见下方:

class object {

    public static $global_filter;

    public function _filterGlobal($class, $method, $callback) {
        if ( !is_object($class::$global_filter) ) {
            $class::$global_filter = new filterable(null);
            # Replace the object being called with the new proxy.
        }
        var_dump($class);
        var_dump($class::$global_filter); // `filterable`
        var_dump(\core\blueprint\object::$global_filter); // Returns same as line above
        die();
        return $class::$global_filter->_add($method, $callback);
    }

}

$class::$global_filter\core\blueprint\object::$global_filter(基类)都返回相同的实例。而我预计 object::$global_filter 为空

我没有使用后期静态绑定来保持一致性(单对象过滤器和全局过滤器的非静态调用方式非常相似)。

This question seems relevant

任何帮助将不胜感激:)

编辑,完整示例

这将是一个具体的类,它扩展了 model,它扩展了 object

<?php
use core\blueprint\model;
class modelMock extends model {
    protected $schema = array();
    public function method($test) {
        return $test;
    }
}

这将是另一个对象(例如控制器),它也扩展了object。它将过滤器应用于model 的所有新实例

<?php
use core\blueprint\object;
class objectMock extends object {

    public function applyFilters() {
        $this->_filterGlobal('core\blueprint\model', 'method', function($self, $chain) {
            $chain->params[0] = 'new param'; // adjust the paramters
            return $chain->next();
        });
    }

}

【问题讨论】:

  • 我不知道是什么问题。我正在使用类似的东西。我们能看到一个具体的类吗?
  • @iRaS 现在正在拼凑一些东西
  • @iRaS 刚刚在问题中添加了一个示例,谢谢!

标签: php static aop class-hierarchy


【解决方案1】:

当我尝试将静态 $global_filter 分配给我想要过滤的后代类时,我的基类对象也得到相同的分配

是的,确实会发生这种情况。静态属性本质上是一个全局变量,被限制在类的命名空间内。遇到全局变量问题通常表明您没有使用最佳解决方案。

要解决您的问题,您可以将过滤器设为(非静态)属性:

$class->$filter = new Whatever();

但与往常一样,通往罗马的道路更多,我建议您寻找替代方法。

【讨论】:

  • 这不是他的解决方案。他希望所有对象都被此过滤器过滤,并且还希望已经实例化的对象。
  • 感谢您澄清静态属性受限于类的命名空间。但是 iras 是对的,我需要将过滤器应用于同一类的所有新对象(尽管不一定已经实例化对象)
【解决方案2】:

我不知道这是否对你有帮助:

class a {
   public static $type;

   public static function setType($class, $newType) {
      $class::$type = $newType;
      var_dump($class::$type);
   }
}
class b {
   public static $type = 'myType';
}

var_dump(b::$type);
a::setType('b', 'yourType');
var_dump(a::$type);

可能是你没有为具体类定义静态属性。

【讨论】:

  • 谢谢你,但我的大多数对象都需要可过滤,所以我不能依赖为每个单独的对象添加静态属性,并且在编写新对象时不能相信其他人这样做对象。
  • 对不起,我猜没有好消息。如果没有在具体类中声明静态属性,我看不到您的要求。它看起来像重新声明,但它是每个类的新静态属性,否则它是父类的静态属性。
  • 啊,好的,我明白了,好的,谢谢你的帮助 :) 我今天会再研究一下
【解决方案3】:

感谢大家的帮助,今天早上我花了一些时间解决了我的问题。这是一种解决方法,但它是这样的:

public function _filterGlobal($class, $method, $callback) {
    if ( !is_object($class::$global_filter[$class]) ) {
        $class::$global_filter[$class] = new filterable(null);
        # Replace the object being called with the new proxy.
    }
    return $class::$global_filter[$class]->_add($method, $callback);
}

因此,基本上为了在子类中获得唯一的静态变量而不必显式定义它们,您可以使用一个数组来存储子类的名称作为键,然后通过 getter 访问这些变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-20
    • 1970-01-01
    • 2021-09-05
    • 2017-03-05
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 2012-11-08
    相关资源
    最近更新 更多