PHP 仅包含特定 class 对象的数组

PHP array with only objects of a specific class

我有一个名为 Rule 的 class,我将要创建一个 RuleContainer class,它实际上是 Rule 对象数组

我想知道是否有创建新 class 的替代方法。有什么(现代)方法可以解决这个问题吗?也就是说,类似于使用 SPL 定义 一个只允许添加特定 class.

对象的数组

如果不是,我应该在我的 RuleContainer 中实现哪个接口 class?

在你的情况下,我会实施 Iterator interface in the RuleContainer, as I've done several times when I needed a sort of Collection<T> as we know it from other (typed) languages. And in the add(Rule $item) or addItem(Rule $item) method I'd make sure with the type definition of the argument (or using instanceof) 要添加的项目的类型 Rule

最适合您任务的 class 是 SplObjectStorage,但它不允许 class 类型提示。

我想,你可以这样做:

class RuleContainer extends SplObjectStorage
{
    function attach(Rule $rule)
    {
         parent::attach($rule);
    }

    function detach(Rule $rule)
    {
         parent::detach($rule);
    }
}

等等。您可以阅读 php.net 上的 SplObjectStorage 界面并决定您将使用什么以及需要覆盖什么。

根据容器的使用模式class,您需要实现以下接口中的一个或多个:

  • Iterator - 将其用作 foreach($container as $key => $value);
  • Countable - 对于 count($container);
  • ArrayAccess - for $container[$key](设置它,得到它,检查它是否isset()unset()它);

PHP 数组例程接口的使用

您可以实现您的目标,例如,ArrayAccess implementation. Together with Iterator它看起来像:

class ArrayStorage implements Iterator, ArrayAccess
{
    private $holder = [];

    private $instanceName;

    public function __construct($instanceName)
    {
        if (!class_exists($instanceName)) {
            throw new \Exception('Class '.$instanceName.' was not found');
        }
        $this->instanceName = $instanceName;
    }
    public function rewind() 
    {
        reset($this->holder);
    }

    public function current() 
    {
        return current($this->holder);
    }

    public function key() 
    {
        return key($this->holder);
    }

    public function next() 
    {
        next($this->holder);
    }

    public function valid() 
    {
        return false !== $this->current();
    }

    public function offsetSet($offset, $value) 
    {
        if (!($value instanceof $this->instanceName)) {
            throw new \Exception('Storage allows only '.$this->instanceName.' instances');
        }
        if (is_null($offset)) {
            $this->holder[] = $value;
        } else {
            $this->holder[$offset] = $value;
        }
    }

    public function offsetExists($offset) 
    {
        return isset($this->holder[$offset]);
    }

    public function offsetUnset($offset) 
    {
        unset($this->holder[$offset]);
    }

    public function offsetGet($offset) 
    {
        return isset($this->holder[$offset]) ? $this->holder[$offset] : null;
    }
}

进程数

所以 - 是的,您正在明确地进行 instanceof 检查,但是 class 的最终用户并不知道这一点。只能在此存储的上下文中对有效实例进行操作(您可以查看 this fiddle 以获取使用示例)。概念是这样的:

$storage = new ArrayStorage('Foo'); //define what we will accept
$storage[] = new Foo; //fine, [] array-writing
$storage['baz'] = new Foo; //fine, key set
foreach ($storage as $key => $value) {
    echo($key. ' => '.PHP_EOL.var_export($value, 1).PHP_EOL);
}
//invalid, will not pass. Either throw exception or just ignore:
$storage['bee'] = new Bar; 

结束失败检查行为由您决定,但我认为,抛出异常是这里的最佳选择,因为它们是可捕获的,因此,最终用户可以决定在这种情况下要做什么。进一步的选择可能是将 Countable 添加到存储中,但它不会改变一般想法。

缺点

缺点 - 不,您将无法 "typehint" 它以某种方式。虽然它很有用,但在文档块中您仍然需要显示您接受哪种实体。在通用语言特性方面,Joe Watkins 提出了 arrayof RFC,它是为 PHP 5.6 版提出的,但不幸的是,它失败了。可能会在下一个版本中重新考虑。

您可以自己制作 RuleContainer(如您所说)并发挥各种聪明才智来手动强制执行它,但您生活在现实世界中,我生活在现实世界中,而您只是 不需要为此需要容器对象,只需使用数组即可。

如果您的问题只是 enforcement 主题对象类型 a lá List<className>() 中的一个 enforcement,您不能在 PHP[=25= 中执行此操作] 老实说,它在发现它的语言中的使用值得商榷(我知道我会因为这样说而投票,但我仍然是对的)//除了它有助于进一步阐明列表的目的//在老实说,我 20 多年的编程经验几乎涵盖了所有语言(机器代码 perl 和 fortran 除外),我可以告诉你这样的结构,根本不值得人力开销,它们可能包括间接的意外负担,超过它们的实际价值:

一个简单的妥协是:不偷懒,开始为数组命名而不是像 tmpList 这样的东西,如果你绝对确定实施一个简单的 testhttp://php.net/manual/en/function.get-class.php 在 forloops 开始你肯定最终使用