skip to Main Content
Deprecated: Creation of dynamic property ... is deprecated 

I’m seeing this more and more, and I’m not sure what I need to do to stop this warning.

This is my 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;
        }
    }
}

This is how I’m instanacing it.

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

Which gives me two messages:

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

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

7

Answers


  1. So the warnings are coming from the constructor adding dynamic class properties. If you don’t have to pass in those fields dynamically and really, it does seem like you’re overcomplicating something simple then try it like this.

    class database {
    
        public $username = "root";
        public $password = "pasword";
        public $port = 3306;
        public $database = 'db_name';
        public $server = 'database.internal';
    }
    
    
    $db = new database();
    

    Is there a reason you needed dynamic parameters? You could also do this:

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

    If you add the parameters ahead of time, they’re not dynamic, and you’re just assigning a value to something already existing.

    This should work now without any warnings.

    
    $db = new database(array(
        'database' => 'db_name',
        'server' => 'database.internal',
    ));
    
    
    Login or Signup to reply.
  2. An alternative solution, which is specific to this example in that the parameters are quite easy to identify. Databases have common parameters that are referenced.

    Using PHP 8 named parameters and Constructor property promotion, allows you to specify all of the possible parameters in the constructor (which is a bit long winded, but great for code completion) and then when creating an instance, the parameter names are fixed…

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

    Then call with

    $db = new database(
        database: 'db_name',
        server: 'database.internal',
    );
    
    Login or Signup to reply.
  3. The warning message you are seeing is related to the use of a feature in PHP called "dynamic properties". Dynamic properties allow you to set and get object properties by using variable names, like you are doing in the __construct method of your database class.

    Quick fix:

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

    To fix this warning, you can remove the use of dynamic properties in your code and use a more modern way of setting object properties.

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

    Alternatively, you can also use the __set and __get magic methods to set and get object properties, like this:

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

    This will allow you to use the $object->property notation to set and get object properties, without triggering the warning message.

    Login or Signup to reply.
  4. You can avoid the need to specify an explicit list of member variables by storing them in a single array, like this:

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

    Then you can instantiate a database object with any params you want:

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

    Of course, you’ll probably want to document what the expected params are, but at least you’ll be able to pass in anything you want, and be able to use it in the future, without changing the class definition.

    Login or Signup to reply.
  5. The warning is telling you that there is a property you are trying to set which isn’t listed at the top of the class.

    When you run this:

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

    It is roughly equivalent to this:

    class database {
    
        public $username = "root";
        public $password = "pasword";
        public $port = 3306;
    }
    
    $db = new database;
    $db->database = 'db_name';
    $db->server = 'database.internal';
    

    The warning is that there is no line in the class definition saying that $db->database or $db->server exist.

    For now, they will be dynamically created as untyped public properties, but in future, you will need to declare them explicitly:

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

    In some rare situations, you actually want to say "the properties of this class are whatever I decide to add at run-time"; in that case, you can use the #[AllowDynamicProperties] attribute, like this:

    #[AllowDynamicProperties]
    class objectWithWhateverPropertiesIWant {
        public function __construct($params = array())
        {
            foreach ($params as $key => $value)
            {
                $this->{$key} = $value;
            }
        }
    }
    
    Login or Signup to reply.
  6. Adding this just above the class{ will fix it:

    #[AllowDynamicProperties]

    Login or Signup to reply.
  7. if you only want the warnings not to be displayed, simply replace this:

    class database {
    

    for this:

    class database extends stdClass {
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search