我有一个名为Rule的类,我即将创建一个RuleContainer类,它实际上是一个Rule对象数组。
我想知道是否有创建新课程的替代方案。有没有(现代)方法来解决这个问题?也就是说,使用SPL来定义只允许添加特定类的对象的数组。
如果没有,我应该在RuleContainer类中实现哪个接口?
答案 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的开头,你肯定最终会使用