PHP数组,只包含特定类的对象

时间:2015-01-23 10:37:11

标签: php arrays spl

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

我想知道是否有创建新课程的替代方案。有没有(现代)方法来解决这个问题?也就是说,使用SPL来定义只允许添加特定类的对象的数组

如果没有,我应该在RuleContainer类中实现哪个接口?

5 个答案:

答案 0 :(得分:2)

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

我想,你可以这样做:

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

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

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

答案 1 :(得分:1)

在你的情况下,我会在RuleContainer中实现Iterator界面,因为我需要一种Collection<T>,因为我们从其他人那里知道它(键入的)语言。在add(Rule $item)addItem(Rule $item)方法中,我确定参数的类型定义(或使用instanceof),要添加的项目是Rule类型

答案 2 :(得分:1)

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

  • Iterator - 将其用作foreach($container as $key => $value);
  • Countable - 适用于count($container);
  • ArrayAccess - $container[$key](设置,获取,检查isset()unset());

答案 3 :(得分:1)

PHP数组例程接口的用法

您可以通过ArrayAccess实施来实现目标。与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;
    }
}

<强> PROCS

所以 - 是的,你正在明确地进行instanceof检查,但你班级的最终用户并不知道。只能在此存储的上下文中对有效实例进行操作(您可以检查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添加到存储中,但它不会改变一般的想法。

并且缺点

下行 - 不,你不能以某种方式“打字”它。虽然它很有用,但在doc块中你还需要显示你接受的实体类型。在一般语言功能方面,Joe Watkins提出了arrayof RFC,它是为PHP 5.6版本提出的,但遗憾的是,它失败了。可能会在下一版本中重新考虑。

答案 4 :(得分:0)

你可以自己制作RuleContainer(如你所说)并做各种各样的聪明来手动执行它,但你生活在我生活在现实世界中的现实世界中你只是不要< / strong>需要一个容器对象,只需使用一个数组。

如果你的问题只是enforcement主题对象中的一个,那么你需要在{<1}} 中执行此操作,并且说实话,这是值得商榷的问题在发现它的语言中(我知道我会因为这样说而被投票,但我仍然是对的)//除了它有助于进一步澄清列表的目的//在所有诚实中我20多年的编程几乎所有语言都有(除了机器码perl和fortran),我可以告诉你这样的结构,并且根本不值得人为开销,而且他们自己可以包括间接意外的负担超过他们的实际价值:

一个简单的妥协是:没有懒惰,开始命名数组比List<className>()更多,如果你是绝对的确定implment简单的tmpList到{{3}在forloops的开头,你肯定最终会使用