繁体   English   中英

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

[英]PHP array with only objects of a specific class

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

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

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

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

我想,你可以这样做:

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

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

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

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

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

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

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;
    }
}

特效

所以 - 是的,你明确地做了instanceof检查,但你班级的最终用户并不知道。 只能在此存储的上下文中操作有效实例(您可以检查此小提琴的使用示例)。 概念就像:

$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提供了一系列RFC ,它是为PHP 5.6版本提出的,但遗憾的是,它失败了。 可能会在下一版本中重新考虑。

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

如果您的问题只是主题对象类型的enforcement类型之一ll List<className>() 您无法在PHP中执行此操作并且说实话它在找到它的语言中有争议的使用(我知道我会得到)我投票赞成这样说,但我仍然是对的)//除了它有助于进一步澄清列表的目的//在所有诚实中,我对几乎所有语言的20多年编程都存在(除了机器码perl和fortran) ),我可以告诉你这样的结构,根本不值得人为开销,他们自己可以包括间接意外的负担超过他们的实际价值:

一个简单的妥协是: 没有懒惰 ,开始命名数组比tmpList更多,如果你是absolultey确定implment一个简单的test http://php.net/manual/en/function.get-class.php在开始您肯定最终会使用的forloops

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM