【问题标题】:PHP Warning Deprecated: Creation of dynamic property is deprecatedPHP 警告已弃用:不推荐创建动态属性
【发布时间】:2023-02-08 12:07:21
【问题描述】:
Deprecated: Creation of dynamic property ... is deprecated 

我越来越多地看到这种情况,但我不确定我需要做什么才能停止此警告。

这是我的课:

class database {

    public $username = "root";
    public $password = "pasword";
    public $port = 3306;

    public function __construct($params = array())
    {

        foreach ($params as $key => $value)
        {
            $this->{$key} = $value;
        }
    }
}

这就是我实例化它的方式。

$db = new database(array(
    'database' => 'db_name',
    'server' => 'database.internal',
));

这给了我两条信息:

Deprecated: Creation of dynamic property database::$database is deprecated 

Deprecated: Creation of dynamic property database::$server is deprecated

【问题讨论】:

  • 你得到的确切警告是什么?
  • 我得到了一些这样的消息,“未知错误类型:[8192] 动态属性数据库的创建::$server 已被弃用,还有一个用于 $server”
  • 稍后在创建该 $database 对象时必须传递其他参数。
  • 您可以在 setter 之前使用类似这样的内容:if (!property_exists($this, $key)) { throw new Exception('Unknown property'); } 它不会修复您的代码,但它至少会让您了解确定其他违规行为的过程。
  • @AlexHowansky 该消息已经命名了正在创建的属性; OP 刚刚将其编辑掉。

标签: php


【解决方案1】:

所以警告来自添加动态类属性的构造函数。如果您不必动态且真实地传递这些字段,那么看起来您确实使简单的事情过于复杂,然后像这样尝试。

class database {

    public $username = "root";
    public $password = "pasword";
    public $port = 3306;
    public $database = 'db_name';
    public $server = 'database.internal';
}


$db = new database();

您是否需要动态参数?你也可以这样做:

class database {

    public $username = "root";
    public $password = "pasword";
    public $port = 3306;
    public $database;
    public $server;

    public function __construct($params = array())
    {

        foreach ($params as $key => $value)
        {
            $this->{$key} = $value;
        }
    }
}

如果您提前添加参数,它们就不是动态的,您只是在为已经存在的东西赋值。

现在应该可以在没有任何警告的情况下工作。


$db = new database(array(
    'database' => 'db_name',
    'server' => 'database.internal',
));

【讨论】:

  • 好的,这摆脱了警告。谢谢。
  • 这也有问题这绝对是一个解决方案,但它会阻碍代码完成
  • @NigelRen 是吗?它将 $db->database 和 $db->server 添加到代码完成选项中。
  • @Johnny3653925,所以在使用new database() 时它有助于完成代码?
  • @Johnny3653925 听起来像是编码镜像。哦,伙计,抱歉开玩笑了。
【解决方案2】:

警告告诉你有一个你试图设置的属性没有列在类的顶部.

当你运行这个:

class database {

    public $username = "root";
    public $password = "pasword";
    public $port = 3306;

    public function __construct($params = array())
    {
        foreach ($params as $key => $value)
        {
            $this->{$key} = $value;
        }
    }
}

$db = new database(array(
    'database' => 'db_name',
    'server' => 'database.internal',
));

它大致等同于:

class database {

    public $username = "root";
    public $password = "pasword";
    public $port = 3306;
}

$db = new database;
$db->database = 'db_name';
$db->server = 'database.internal';

警告是类定义中没有一行表明存在$db->database$db->server

现在,他们将动态地创建为无类型的公共属性,但将来,您需要显式声明它们:

class database {
    public $database;
    public $server;
    public $username = "root";
    public $password = "pasword";
    public $port = 3306;

    public function __construct($params = array())
    {
        foreach ($params as $key => $value)
        {
            $this->{$key} = $value;
        }
    }
}

$db = new database(array(
    'database' => 'db_name',
    'server' => 'database.internal',
));

在极少数情况下,您实际上想说“此类的属性是我决定在运行时添加的任何内容”;在这种情况下,您可以使用 #[AllowDynamicProperties] 属性,如下所示:

#[AllowDynamicProperties]
class objectWithWhateverPropertiesIWant {
    public function __construct($params = array())
    {
        foreach ($params as $key => $value)
        {
            $this->{$key} = $value;
        }
    }
}

【讨论】:

    【解决方案3】:

    您看到的警告消息与 PHP 中名为“dynamic properties”的功能的使用有关。动态属性允许您使用变量名设置和获取对象属性,就像您在数据库类的 __construct 方法中所做的那样。

    快速解决:

    public function __construct(array $params)
    {
        $this->username = $params['username'] ?? null;
        $this->password = $params['password'] ?? null;
        $this->port = $params['port'] ?? null;
    }
    

    要解决此警告,您可以在代码中删除动态属性的使用,并使用更现代的方式来设置对象属性。

    Named arguments:

    class database
    {
        public function __construct(
            public string $username,
            public string $password,
            public int $port,
        ) {}
    }
    
    $db = new database(
        username: 'root',
        password: 'password',
        port: 3306,
    );
    

    或者,您也可以使用 __set__get 魔术方法来设置和获取对象属性,如下所示:

    public function __set($key, $value)
    {
        $this->$key = $value;
    }
    
    public function __get($key)
    {
        return $this->$key;
    }
    

    这将允许您使用 $object->property 符号来设置和获取对象属性,而不会触发警告消息。

    【讨论】:

    • 我将其从 {$key} 更改为 $key 但仍然看到相同的警告。
    • 有一点误会; “动态属性”在这种情况下不是指使用名称变量访问对象属性,它指的是获取或设置属性尚未宣布.只要在类的顶部声明$id$propName='id'; $this->{$propName}=42;就可以;如果 $id$this->id=42; 将发出警告不是宣布在班级的顶部。
    • 只是为了对投票的人重申,这个答案具有误导性,因为它正在使用动态属性的错误定义.写$this->{$key} = $value不是是什么触发了通知,写 $this->database - $value 会触发完全相同的信息.
    【解决方案4】:

    一个替代解决方案,它特定于此示例,因为参数非常容易识别。数据库具有引用的公共参数。

    使用 PHP 8 命名参数和 Constructor 属性提升,允许您在构造函数中指定所有可能的参数(这有点冗长,但非常适合代码完成),然后在创建实例时,参数名称是固定的。 .

    class database
    {
        public function __construct(
            private string $database = '',
            private string $server = '',
            private string $port = '',
            private string $user = '',
            private string $password = ''
        ) {
        }
    }
    

    然后打电话给

    $db = new database(
        database: 'db_name',
        server: 'database.internal',
    );
    

    【讨论】:

    • 如果我这样做,那么我是否无法从类外部访问私有变量的值。我必须为每个访问器添加一些访问器。
    • @Johnny3653925,您可以根据需要将它们公开,但这通常违反 OO 实践,因为它允许其他类混淆您拥有的值。 (stackoverflow.com/questions/4361553/… 有一些信息)
    • 好吧,这是一个更大的图景来考虑。我会做更多的研究。
    • 在这个网站上称某些东西为“替代解决方案”有点令人困惑,因为答案的顺序可以改变并且可以添加新的答案。理想情况下,答案应该是独立的,并解释问题是什么,以及如何解决问题。
    • @IMSoP,它是一种替代解决方案,因为它不使用动态属性,而动态属性正是 OP 试图使用的。与任何其他答案无关。
    【解决方案5】:

    您可以通过将成员变量存储在单个数组中来避免指定显式成员变量列表的需要,如下所示:

    class database {
        public $data;
    
        public function __construct($params = array())
        {
            foreach ($params as $key => $value)
            {
                $this->data[$key] = $value;
            }
        }
    }
    

    然后你可以用你想要的任何参数实例化一个 database 对象:

    $db = new database(array(
        'database' => 'db_name',
        'server' => 'database.internal',
        'foo' => 'bar', // etc.
    ));
    

    当然,您可能想要记录预期的参数是什么,但至少您将能够传入任何您想要的东西,并且能够在将来使用它,而无需更改类定义。

    【讨论】:

    • 这绝对是一个解决方案,但它会阻碍代码完成
    【解决方案6】:

    将其添加到 class{ 上方将修复它:

    #[允许动态属性]

    【讨论】:

    • 您的答案可以通过其他支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写出好的答案的信息in the help center
    【解决方案7】:

    简单地替换这个:

    class database {
    

    为了这:

    class database extends stdClass {
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      • 2021-08-09
      • 2020-04-13
      • 2017-03-12
      • 1970-01-01
      • 2019-01-28
      相关资源
      最近更新 更多