简体   繁体   English

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

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

I have a class called Rule and I'm about to create a RuleContainer class that's actually an array of Rule objects . 我有一个名为Rule的类,我即将创建一个RuleContainer类,它实际上是一个Rule对象数组

I wonder if there is an alternative of creating a new class. 我想知道是否有创建新课程的替代方案。 Is there any (modern) way to approach this problem? 有没有(现代)方法来解决这个问题? That is, something like using SPL to define an array that only allows adding objects of a specific class . 也就是说,使用SPL定义一个只允许添加特定类对象的数组

If not, which interface should I implement in my RuleContainer class? 如果没有,我应该在RuleContainer类中实现哪个接口?

The most suitable class for your task would be SplObjectStorage , but it doesn't allow for class typehint. 您的任务最合适的类是SplObjectStorage ,但它不允许类typehint。

I think, you could do as follow: 我想,你可以这样做:

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

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

and so on. 等等。 You can read for SplObjectStorage interface on php.net and decide, what will you use and what needs overriding. 您可以在php.net上阅读SplObjectStorage界面并决定,您将使用什么以及需要覆盖什么。

In your case, I would implement the 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. 在你的情况下,我会在RuleContainer实现Iterator接口,因为我需要一种Collection<T>因为我们从其他(类型)语言中知道它。 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 ) that the item to be added is of type Rule . add(Rule $item)addItem(Rule $item)方法中,我确保使用参数的类型定义(或使用instanceof ),要添加的项目是Rule类型。

Depending on the usage patterns for your container class, you need to implement one or more of these interfaces: 根据容器类的使用模式,您需要实现以下一个或多个接口:

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

Usage of PHP array-routines interfaces PHP数组例程接口的用法

You may achieve your goal with, for example, ArrayAccess implementation. 例如,您可以通过ArrayAccess实现来实现目标。 Together with Iterator it will look like: 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 特效

So - yes, you are doing instanceof check explicitly, but end user of your class doesn't know about that. 所以 - 是的,你明确地做了instanceof检查,但你班级的最终用户并不知道。 It will only be possible to operate on valid instances in context of this storage (you can check this fiddle for usage sample). 只能在此存储的上下文中操作有效实例(您可以检查此小提琴的使用示例)。 Concept is like: 概念就像:

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

End fail-check behavior is up to you, but, my opinion, throwing exception is the best choice here as they are catchable, thus, end user may decide what to do in this case. 结束失败检查行为取决于您,但是,我认为,抛出异常是最好的选择,因为它们是可捕获的,因此,最终用户可以决定在这种情况下该做什么。 Further option may be to add Countable to the storage, but it won't change generic idea. 进一步的选择可能是将Countable添加到存储中,但它不会改变通用的想法。

And cons 和利弊

Downside - no, you will not be able to "typehint" it somehow. 缺点 - 不,你不能以某种方式“打字”它。 While it is useful, in doc blocks you still will need to show what kind of entity are you accepting. 虽然它很有用,但在doc块中你还需要显示你接受的实体类型。 In terms of general language features, there is arrayof RFC , by Joe Watkins, which was proposed for PHP version 5.6, but, unfortunately, failed. 就通用语言功能而言,Joe Watkins提供了一系列RFC ,它是为PHP 5.6版本提出的,但遗憾的是,它失败了。 May be it will be reconsidered in next versions releases. 可能会在下一版本中重新考虑。

You can make RuleContainer yourself (as you say) and do all sorts of cleverness to manually enforce it but you live in the real world I live in the real world and you simply don't need a container object for this, just use an array. 你可以自己创建RuleContainer (如你所说)并做各种聪明来手动强制执行它但你生活在我现实生活中的现实世界你根本不需要容器对象,只需使用一个数组。

If your problem is simply one of enforcement of the subject object type a lá List<className>() you can't do this in PHP and to be honest it's of debatable use in the languages where it is found (I know I will get down voted for saying this, but I will still be right) //excepting it helps further clarify the purpose of the list// In all honesty my 20+ years of programming across almost all the languages there is (except machine code perl and fortran), I can tell you such constructs and simply not worth the human overhead and themselves can include indirect unintended burdens way over their actual worth: 如果您的问题只是主题对象类型的enforcement类型之一ll List<className>() 您无法在PHP中执行此操作并且说实话它在找到它的语言中有争议的使用(我知道我会得到)我投票赞成这样说,但我仍然是对的)//除了它有助于进一步澄清列表的目的//在所有诚实中,我对几乎所有语言的20多年编程都存在(除了机器码perl和fortran) ),我可以告诉你这样的结构,根本不值得人为开销,他们自己可以包括间接意外的负担超过他们的实际价值:

An easy compromise is: no laziness , start naming the array more than something like tmpList and if you are absolultey determined implment a simple test to http://php.net/manual/en/function.get-class.php at the start of the forloops you surely eventually use 一个简单的妥协是: 没有懒惰 ,开始命名数组比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