PHP Warning Deprecated: Creation of dynamic property is deprecated

回答 7 浏览 9474 2022-12-21
Deprecated: Creation of dynamic property ... is deprecated 

我越来越多地看到这种情况,我不知道我需要做什么来停止这种警告。

这是我的class:

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
Johnny 3653925 提问于2022-12-21
你得到的确切警告是什么?jbrahy 2022-12-21
我得到几个这样的," Unknown error type: [8192] Creation of dynamic property database::$server is deprecated and one for $server also"。Johnny 3653925 2022-12-21
当你创建$database对象时,必须要有额外的参数,你要在稍后传入这些参数。jbrahy 2022-12-21
你可以在setter前面加上类似的东西。if (!property_exists($this, $key)) { throw new Exception('Unknown property'); } 它不会修复你的代码,但它至少会给你一个钩子,让你在钉住你的其他违规行为的过程。Alex Howansky 2022-12-21
@AlexHowansky 这条信息已经命名了正在创建的属性,OP只是把它编辑掉了。IMSoP 2022-12-21
7 个回答
#1楼
得票数 6

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

当你运行这个时:

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;
        }
    }
}
IMSoP 提问于2022-12-21
IMSoP 修改于2022-12-21
#2楼 已采纳
得票数 5

因此,警告来自于构造函数添加动态类属性。如果你不需要动态传入这些字段,而且真的,你似乎把简单的事情搞得太复杂了,那就这样试试吧。

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',
));

jbrahy 提问于2022-12-21
好了,这就摆脱了警告。谢谢你。Johnny 3653925 2022-12-21
这也存在这肯定是一个解决方案,但它会阻碍代码的完成的问题。Nigel Ren 2022-12-21
@NigelRen 它是这样的?它把$db->database和$db->server加入了代码完成选项。Johnny 3653925 2022-12-21
@Johnny3653925,所以当使用new database()时,对代码完成有帮助吗?Nigel Ren 2022-12-21
@Johnny3653925 听起来像一个编码镜。 哦,伙计,对不起,坏的笑话。jbrahy 2022-12-21
#3楼
得票数 2

你可以通过将成员变量存储在一个数组中来避免指定一个明确的成员变量列表,就像这样:

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.
));

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

kmoser 提问于2022-12-21
这绝对是一个解决方案,但它会阻碍代码的完成。Johnny 3653925 2022-12-21
#4楼
得票数 2

你所看到的警告信息与使用PHP中的一个功能有关,这个功能叫做"动态属性"。动态属性允许你通过使用变量名来设置和获取对象属性,就像你在数据库类的__construct方法中做的那样。

快捷的解决方法:

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

为了解决这个警告,你可以在你的代码中删除对动态属性的使用,并使用更现代的方式来设置对象属性。

命名的参数

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符号来设置和获取对象的属性,而不会触发警告信息。

Gaios 提问于2022-12-21
Gaios 修改于2022-12-21
我把它从{$key}改成了只有$key,但还是看到了同样的警告。Johnny 3653925 2022-12-21
有一点误会;在这种情况下,“动态属性”不是指使用名称变量访问对象属性,它是指获取或设置尚未声明 的属性。只要在类的顶部声明$id$propName='id'; $this->{$propName}=42; 就可以;如果在类的顶部声明$id$this->id=42; 将发出警告。IMSoP 2022-12-21
我想对投票的人重申一下,这个答案有误导性,因为它使用了动态属性的错误定义。写$this->{$key} = $value不是触发通知的原因,写$this->database - $value会触发完全相同的信息IMSoP 2022-12-21
#5楼
得票数 1

一个替代性的解决方案,它是针对这个例子的,因为参数是很容易识别的。数据库有共同的参数,可供参考。

使用PHP 8命名的参数和构造函数属性推广,可以在构造函数中指定所有可能的参数(这有点啰嗦,但对代码的完成很有帮助),然后在创建实例时,参数的名字是固定的...

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',
);
Nigel Ren 提问于2022-12-21
如果我这样做,那么我就不能从类外访问私有变量的值。我将不得不为每个变量添加一些访问器。Johnny 3653925 2022-12-21
@Johnny3653925,如果你想的话,你可以把它们变成公共的,但这通常是违反OO惯例的,因为它允许其他的类来扰乱你的值。(stackoverflow.com/questions/4361553/…有一些信息)Nigel Ren 2022-12-21
好吧,这是个更大的问题,需要考虑。我将做一些更多的研究。Johnny 3653925 2022-12-21
在这个网站上,把一些东西称为"替代解决方案"是有点混乱的,因为答案的顺序可以改变,而且还可以添加新的答案。理想情况下,答案应该是独立的,并解释问题是什么,以及如何解决这个问题。IMSoP 2022-12-21
@IMSoP,这是一个替代方案,因为它不使用动态属性,而这正是OP想要使用的。与其他答案没有关系。Nigel Ren 2022-12-21
#6楼
得票数 1

在class{的上方添加这个就可以解决这个问题了。

#[\AllowDynamicProperties]

Katufo Prem 提问于2023-01-25
您的答案可以通过其他支持信息得到改进。请编辑以添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到更多关于如何写出好的答案的信息。Community 2023-01-28
#7楼
得票数 0

简单地将这个:

class database {

替换为:

class database extends \stdClass {
Ale DC 提问于2023-02-08
标签
php