簡體   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