PHP'instanceof'失败,类不变

时间:2010-06-09 01:38:56

标签: php oop strong-typing

我正在研究一个我试图尽可能强烈打字的框架。 (我在PHP中工作并从C#中学习了一些我喜欢的想法并试图在这个框架中使用它们。)我正在创建一个Collection类,它是域实体/对象的集合。它有点模仿.Net中的List<T>对象。

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

此框架中的所有集合都需要具有某些基本功能,例如添加,删除,迭代。我创建了一个界面,但发现我无法执行以下操作:

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变量。

6 个答案:

答案 0 :(得分:3)

另一种解决方法是:

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

只是'因为它是常量并不意味着你不能把它放在一个变量中片刻以满足解析器。

答案 1 :(得分:2)

  

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

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

如果您继续沿着这条路前进,也许您应该考虑使用PHP提供给您的工具。例如,有ArrayObject,您可以继承并覆盖所需的方法,以确保只有正确输入的内容才能进入数组。 ArrayObjects可以在PHP中的任何地方使用,可以使用普通数组。此外,已经为您编写了基础的部分。

The rest of the Standard PHP Library可能会引起您的兴趣,尤其是SplObjectStorage课程。

答案 2 :(得分:1)

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

$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属性。)

答案 3 :(得分:1)

它应该是这样的

public function add(ICollection $ obj){

}

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

答案 4 :(得分: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()来解决{{1}的奇怪问题或者甚至self::type总是想要返回基类self::$_type类,所以这可能会有效:

Collection

答案 5 :(得分:-2)

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