【问题标题】:How to avoid dynamic properties in PHP (raise an Error when setting an undeclared property)如何避免 PHP 中的动态属性(设置未声明的属性时引发错误)
【发布时间】:2012-02-26 12:46:14
【问题描述】:

例子:

error_reporting(E_ALL | E_STRICT);
class Test {}
$obj = new Test();
$obj->undeclared = "oops";    // I want an error here !! :(
echo $obj->algo;              // oops 

我在 PHP 5.2.11 和 5.3.0 上对其进行了测试。

我不希望我的对象中有动态属性。
在这种情况下是否可以强制 PHP 引发错误?

【问题讨论】:

  • $obj->undeclared 是如何给您带来问题的?
  • 类测试{ public $myVar; } $obj->my_var = TRUE; /* 错字 / if($obj->myVar) { / 哦哦! */ }
  • 你需要一个好的 IDE 来防止这样的错字。
  • 你能告诉我一个能够做到这一点的 IDE 吗?我正在使用 Zend Studio(当然,你有代码完成功能,但对每个属性都使用 Ctrl+Space 只是因为如果你打错了 PHP 不会告诉你是矫枉过正)
  • 情况其实更糟。如果您将此示例更改为读取未定义的属性而不是尝试写入它,您实际上会收到“通知”级别的错误消息:“通知:未定义属性:Test::$B ...”。所以 PHP 实际上将未定义的读取引用视为错误,将未定义的写入引用视为成功。所以,如果我错了,请纠正我,但 PHP 实际上是不一致的,因此有一个错误。

标签: php dynamic properties


【解决方案1】:

使用__set() ?

<?php
class Test {

    public $bar;

    public function __set($name, $value) {
        throw new Exception('Cant set!');
    }
}

$obj = new Test;
$obj->bar = 'foo';
$obj->foo = 'evil';
?>

【讨论】:

  • 是的,这会起作用,但是我需要更改我的所有类以添加该功能,这不好。这应该由 PHP 本地完成。
  • 绝招!!!!检查它是否“正常继承”,所以我将在我的基类中使用它! :)
  • 我认为语言让您决定如何分配不存在或不可访问的属性可能会很好。但我认为如果这是默认行为会更好,然后可以使用一些配置选项为定义的类启用属性的动态设置
  • @Enrique 这有点象征 PHP 的“松散”,它默认允许这样做;也就是说,对于一个在接触课程之前使用 PHP 几年的人来说,预计会出现这种行为 (YMMV)。至少现在你可以把这个答案的方法放在一个 Trait 中,供你想要的所有类使用/继承。
  • 不幸的是,@Enrique 在发布此消息时我不相信存在特征。
【解决方案2】:

对你的错误信息多加注意,你可以帮助你自己编码。将以下内容作为您的基类设置:

  1. 防止使用此类覆盖您的属性
  2. 保护变量的拼写错误(尤其是驼峰式错误) 例如 $this->callerID 按预期返回,但 $this->callerId 抛出异常并防止代码错误。
    public function __set($name,$value) {
        switch ($name) {
            default:
                // we don't allow any magic properties set or overwriting our properties
                try {
                    $error = "Assignment of {$name} in " . static::class . ' not allowed because it is a magic variable or read-only property.';
                    throw new \RuntimeException($error);
                } catch ( \RuntimeException $e ) {
                    echo 'Caught exception: ' . $e->getMessage() . PHP_EOL;
                }

        }
    }

    public function __get($name)
    {
        switch ($name) {
            default:
                // we don't allow any magic properties
                try {
                    $error = "var {$name} is not a property of " . static::class . '.';
                    throw new \RuntimeException($error);
                } catch ( \RuntimeException $e ) {
                    echo 'Caught exception: ' . $e->getMessage() . PHP_EOL;
                }
        }
        return null;
    }

    public function __isset($name)
    {
        switch ($name) {
            default:
                return false;
        }
    }

【讨论】:

    【解决方案3】:

    通过“我不希望我的对象中有动态属性”。我假设您的意思是您不希望您的对象变量永远未定义?如果是这种情况,那么只需实例化所有类变量。如果您真的担心它们是恒定的而不是动态的,您甚至可以将它们设为静态。

    如果你试图访问一个不存在的对象变量,那么 PHP 抛出一个错误。 radmen 建议的答案实际上是这样,PHP 不会抛出错误,而是动态地为您动态创建未定义的对象变量。

    【讨论】:

    • 没有。当我试图设置一个未在我的类中声明的属性时,我想要一个错误/通知/警告(也就是说,我不希望我的对象中有动态属性,如果没有在我的类中声明,那么它不应该存在,从不)。如果我想要,那么我将使用 __set 和 __get。
    • 嗯,PHP 确实可以满足您的需求。您可能需要将 E_WARNING 添加到错误报告中才能显示。
    • 不,它没有,如果您阅读我的示例,您会看到我添加了包含 E_WARNING 的 E_ALL(我还添加了 E_STRICT,因为它是唯一不包含在 E_ALL 中的,至少在 5.4 之前)
    • 抱歉,我的假设似乎合乎逻辑,但您是对的。仔细研究之后,Shiplu 提出了最好的解决方案,使用 __set() 报错。但是,它不一定需要在基类中,如果您愿意,您可以让它实际抛出异常。
    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-30
    • 2012-04-14
    • 1970-01-01
    相关资源
    最近更新 更多