我正在开发一个框架,我正在尝试尽可能强地输入该框架。 (我正在 PHP 中工作,并从 C# 中汲取了一些我喜欢的想法,并尝试在这个框架中利用它们。)
我正在创建一个 Collection 类,它是域实体/对象的集合。它有点模仿 .Net 中的 List
对象。
我遇到了一个阻碍我输入这门课的障碍。如果我有一个 UserCollection,它应该只允许 User 对象进入其中。如果我有一个 PostCollection,它应该只允许 Post 对象。
这个框架中的所有Collections都需要具备一定的基本功能,比如添加、删除、迭代等。我创建了一个界面,但发现我无法执行以下操作:
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();
}
}
}
当我尝试运行此代码时,我在 instanceof
语句中收到语法错误、意外的 T_STRING、期望 T_VARIABLE 或“$”
。对这个问题进行一些研究,看起来原因的根源是 $obj instanceof self
对于针对该类进行测试是有效的。看来 PHP 没有处理表达式中的整个 self::type
常量语句。在 self::type
变量周围添加括号会引发有关意外“(”的错误。
一个明显的解决方法是不使 type
变量成为常量。表达式 $type
被声明为变量)。
>$obj instanceof $this->type 工作得很好(当然, 因为我想将值定义为常量,以避免以后变量发生任何可能的变化。有什么想法可以实现这一点,或者我是否将 PHP 限制在这方面?有没有一种方法可以“逃避”? " 或者封装 self::this
以便 PHP 在处理它时不会死掉?
更新
根据反馈,我想到了一些可以尝试的东西 - 下面的代码可以工作 ?
任何人都可以想出
- 一个不这样做的原因,
- 一个最终不起作用的原因,或者
- 一个更好的方法来完成这个
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:
将上面的代码投入生产后,结果证明它不起作用 我测试的时候不知道它是如何工作的,但它根本不起作用。我认为我一直坚持使用受保护的变量。
I'm working on a framework that I'm trying to type as strongly as I possibly can. (I'm working within PHP and taking some of the ideas that I like from C# and trying to utilize them within this framework.)
I'm creating a Collection class that is a collection of domain entities/objects. It's kinda modeled after the List<T>
object in .Net.
I've run into an obstacle that is preventing me from typing this class. If I have a UserCollection, it should only allow User objects into it. If I have a PostCollection, it should only allow Post objects.
All Collections in this framework need to have certain basic functions, such as add, remove, iterate. I created an interface, but found that I couldn't do the following:
interface ICollection { public function add($obj) }
class PostCollection implements ICollection { public function add(Post $obj) {} }
This broke it's compliance with the interface. But I can't have the interface strongly typed because then all Collections are of the same type. So I attempted the following:
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();
}
}
}
When I attempt to run this code, I get syntax error, unexpected T_STRING, expecting T_VARIABLE or '$'
on the instanceof
statement. A little research into the issue and it looks like the root of the cause is that $obj instanceof self
is valid to test against the class. It appears that PHP doesn't process the entire self::type
constant statement in the expression. Adding parentheses around the self::type
variable threw an error regarding an unexpected '('.
An obvious workaround is to not make the type
variable a constant. The expression $obj instanceof $this->type
works just fine (if $type
is declared as a variable, of course).
I'm hoping that there's a way to avoid that, as I'd like to define the value as a constant to avoid any possible change in the variable later. Any thoughts on how I can achieve this, or have I take PHP to it's limit in this regard? Is there a way of "escaping" or encapsulating self::this
so that PHP won't die when processing it?
UPDATE
Based on the feedback, I thought of something to try -- the code below works!
Can anyone think of
- a reason not to do this,
- a reason this won't ultimately work, or
- a better way to pull this off?
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();
}
}
}
UPDATE #2:
After putting the code above into production, it turns out it doesn't work. I have no idea how it worked when I tested it, but it doesn't work at all. I'm stuck with using a protected
variable, I think.
发布评论
评论(6)
另一个解决方法是:
仅仅因为它是一个常量并不意味着您不能暂时将其放入变量中以满足解析器的要求。
Another workaround is to do:
Just 'cause it's a constant doesn't mean you can't put it in a variable for a moment to satisfy the parser.
我也对这种行为感到惊讶,但这应该有效:
编辑:
你可以做
但你正在打开复杂计。这会产生额外的开销,即为
PostCollection
的每个实例创建实例$type
变量(不,您不能只将static
添加到代码>$type
属性)。I'm surprised by this behavior as well, but this should work:
EDIT:
You could do
But you're turning on the complicometer. This has the additional overhead of creating an instance
$type
variable for each instance ofPostCollection
(and no, you cannot just addstatic
to the$type
property).用一种语言编写另一种语言通常不是一个好主意。 PHP 中不需要集合。
如果您继续沿着这条路走下去,也许您应该考虑使用 PHP 提供的工具。例如,有 ArrayObject,您可以继承并覆盖它需要方法来确保只有正确键入的内容才能进入数组。 ArrayObjects 可以在 PHP 中任何可以使用普通数组的地方使用。此外,底层的零碎内容已经为您编写好了。
标准 PHP 库的其余部分 您可能会感兴趣,特别是 SplObjectStorage 类。
It's generally not a good idea to write one language in another language. You don't need Collections in PHP.
If you're going continue down that road, perhaps you should consider using tools supplied to you by PHP. For example, there's ArrayObject, which you can inherit from and override the required methods to ensure that only properly typed things enter the array. ArrayObjects can be used anywhere in PHP where a normal array can be used. Also, the underlying bits and pieces have already been written for you.
The rest of the Standard PHP Library may be of some interest to you, the SplObjectStorage class in particular.
它应该很容易像这样
public function add(ICollection $obj){
}
现在,如果您尝试向函数 add 添加一个不是 Icollection 实例的对象(这是一个示例),那么在您到达之前它就会失败使用instanceof进行检查。
it should readly be like this
public function add(ICollection $obj){
}
now if you try to add an object to the function add that is not an instance of Icollection(thats an example) then it will fail, before you even get to check using the instanceof.
使用静态,这也可以正常工作:
实际上,您可能想在
Collection
类上定义add()
方法,这意味着您必须使用get_class()
来解决self::type
的一些奇怪问题,甚至self::$_type
总是想返回基本的无论如何,Collection
类,所以这可能会起作用:This also works correctly, using a static:
And actually, you probably want to define your
add()
method on theCollection
class anyway, which means you'll have to useget_class()
to get around some weirdness withself::type
or evenself::$_type
always wanting to return the baseCollection
class anyway, so this would probably work:尝试使用 PHP 的 is_a 函数而不是 instanceof,因为它需要一个字符串作为类名。
Try using PHP's is_a function instead of instanceof as that expects a string as the Class name.