PHP“实例”类常量失败

发布于 2024-09-05 01:13:40 字数 2108 浏览 5 评论 0 原文

我正在开发一个框架,我正在尝试尽可能强地输入该框架。 (我正在 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 在处理它时不会死掉?

更新

根据反馈,我想到了一些可以尝试的东西 - 下面的代码可以工作 ?

任何人都可以想出

  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:

将上面的代码投入生产后,结果证明它不起作用 我测试的时候不知道它是如何工作的,但它根本不起作用。我认为我一直坚持使用受保护的变量。

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

  1. a reason not to do this,
  2. a reason this won't ultimately work, or
  3. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

眼前雾蒙蒙 2024-09-12 01:13:40

另一个解决方法是:

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

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

Another workaround is to do:

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

Just 'cause it's a constant doesn't mean you can't put it in a variable for a moment to satisfy the parser.

落在眉间の轻吻 2024-09-12 01:13:40

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

$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();
        }
    }
}

但你正在打开复杂计。这会产生额外的开销,即为 PostCollection 的每个实例创建实例 $type 变量(不,您不能只将 static 添加到 代码>$type属性)。

I'm surprised by this behavior as well, but this should work:

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

EDIT:

You could do

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();
        }
    }
}

But you're turning on the complicometer. This has the additional overhead of creating an instance $type variable for each instance of PostCollection (and no, you cannot just add static to the $type property).

み青杉依旧 2024-09-12 01:13:40

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

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

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

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

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.

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.

琉璃梦幻 2024-09-12 01:13:40

它应该很容易像这样

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.

新人笑 2024-09-12 01:13:40

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

<?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());

实际上,您可能想在 Collection 类上定义 add() 方法,这意味着您必须使用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());

This also works correctly, using a static:

<?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());

And actually, you probably want to define your add() method on the Collection class anyway, which means you'll have to use get_class() to get around some weirdness with self::type or even self::$_type always wanting to return the base Collection class anyway, so this would probably work:

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());
谜泪 2024-09-12 01:13:40

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

Try using PHP's is_a function instead of instanceof as that expects a string as the Class name.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文