5

我正在开发一个框架,我试图尽可能地强输入。(我在 PHP 中工作,并从 C# 中获取我喜欢的一些想法,并尝试在这个框架中利用它们。)我正在创建一个 Collection 类,它是域实体/对象的集合。它有点模仿List<T>.Net 中的对象。

我遇到了阻碍我输入这门课程的障碍。如果我有一个 UserCollection,它应该只允许用户对象进入它。如果我有 PostCollection,它应该只允许 Post 对象。

这个框架中的所有Collection都需要具备一定的基本功能,比如add、remove、iterate。我创建了一个界面,但发现我无法执行以下操作:

interface ICollection { public function add($obj) }
class PostCollection implements ICollection { public function add(Post $obj) {} }

这破坏了它对界面的遵守。但是我不能强类型化接口,因为所有集合都是同一类型。所以我尝试了以下方法:

interface ICollection { public function add($obj) }
abstract class Collection implements ICollection { const type = 'null'; }
class PostCollection extends Collection {
 const type = 'Post';
 public function add($obj) {
  if(!($obj instanceof self::type)) {
   throw new UhOhException();
  }
 }
}

当我尝试运行这段代码时,我得到syntax error, unexpected T_STRING, expecting T_VARIABLE or '$'instanceof声明。对该问题进行一些研究,看起来原因的根源是$obj instanceof self对类进行测试是有效的。PHP 似乎没有处理self::type表达式中的整个常量语句。在变量周围添加括号会self::type引发有关意外“(”的错误。

一个明显的解决方法是不要使type变量成为常量。该表达式$obj instanceof $this->type工作得很好($type当然,如果被声明为变量)。

我希望有一种方法可以避免这种情况,因为我想将该值定义为一个常量,以避免以后对变量进行任何可能的更改。关于如何实现这一点的任何想法,或者在这方面我是否将 PHP 发挥到了极限?有没有一种“转义”或封装的方法,self::this以便 PHP 在处理时不会死?

更新根据下面的反馈,我想到了一些尝试——下面的代码有效!谁能想到 1) 不这样做的理由,2) 这最终不会奏效的原因,或 3) 更好的方法来实现这一目标?

interface ICollection { public function add($obj) }
abstract class Collection { const type = null; protected $type = self::type; }
class PostCollection extends Collection {
 const type = 'Post';
 public function add($obj) {
  if(!($obj instanceof $this->type)) {
   throw new UhOhException();
  }
 }
}

更新#2:将上面的代码投入生产后,结果证明它不起作用。当我测试它时,我不知道它是如何工作的,但它根本不起作用。我想我坚持使用protected变量。

4

6 回答 6

3

另一种解决方法是:

$type = self::type;
if (!($obj instanceof $type))

仅仅因为它是一个常量并不意味着您不能暂时将其放入变量中以满足解析器的要求。

于 2010-06-09T01:41:53.227 回答
2

我也对这种行为感到惊讶,但这应该有效:

$type = self::type;
if(!($obj instanceof $type)) {
    throw new UhOhException();
}

编辑:

你可以做

abstract class Collection {
    const type = null;
    protected $type = self::type;
}
class PostCollection extends Collection {
    const type = "User";
    public function add($obj) {
        if(!($obj instanceof $this->type)) {
            throw new WhateverException();
        }
    }
}

但你正在打开复杂度计。这具有为每个实例创建实例$type变量的额外开销PostCollection(不,您不能只添加static$type属性中)。

于 2010-06-09T01:41:38.593 回答
2

我正在创建一个 Collection 类,它是域实体/对象的集合。它有点模仿List<T>.Net 中的对象。

用另一种语言编写一种语言通常不是一个好主意。您不需要 PHP 中的集合。

如果您要继续走这条路,也许您应该考虑使用 PHP 提供给您的工具。例如,有ArrayObject,您可以从它继承并覆盖所需的方法,以确保只有正确键入的内容才能进入数组。ArrayObjects 可以在 PHP 中任何可以使用普通数组的地方使用。此外,已经为您编写了底层的点点滴滴。

您可能对标准 PHP 库的其余部分感兴趣,尤其是SplObjectStorage类。

于 2010-06-09T03:02:29.387 回答
1

它应该是这样的

公共函数添加(ICollection $obj){

}

现在,如果您尝试向函数 add 添加一个不是 Icollection 实例的对象(这是一个示例),那么它将失败,甚至在您使用 instanceof 进行检查之前。

于 2010-06-09T09:31:36.057 回答
0

这也可以正常工作,使用静态:

<?php

interface ICollection { 
  public function add($obj); 
}
abstract class Collection implements ICollection { 
  static protected $_type = 'null'; 
}
class PostCollection extends Collection {
 static protected $_type = 'Post';
 public function add($obj) {
  if(!($obj instanceof self::$_type)) {
   throw new UhOhException();
  }
 }
}


class Post {}

$coll = new PostCollection();
$coll->add(new Post());

实际上,您可能无论如何都想add()在类上定义您的方法Collection,这意味着您必须使用get_class()来解决一些奇怪的问题,self::type甚至self::$_type总是想要返回基Collection类,所以这可能会起作用:

abstract class Collection implements ICollection { 
  const type = 'null'; 
  public function add($obj) {
   $c = get_class($this);
   $type = $c::type;
   if(!($obj instanceof $type)) {
    throw new UhOhException();
   }
  }
}

class PostCollection extends Collection {
 const type = 'Post';
}
class Post {}

$coll = new PostCollection();
$coll->add(new Post());
于 2010-06-09T09:40:19.563 回答
-1

尝试使用 PHP 的is_a函数而不是 instanceof,因为它需要一个字符串作为类名。

于 2010-06-09T01:45:36.370 回答