Search code examples
phpphp-8.2

"Cannot use temporary expression in write context" when assigning to prop on class instance defined as constant


The following code snippet will produce an error on PHP 8.2:

<?php

const foo = new stdClass();

foo->bar = 'baz';

echo foo->bar;

?>

I would expect that an error would not occur, since I am assigning to the prop rather than trying to reassign the constant.

If I create a new class, extending stdClass, and add the following method:

class extendsStdClass extends stdClass {
    public function set(string $name, mixed $value) {
      $this->$name = $value;
    }
}

then I can assign to props using the following syntax:

<?php

const foo = new extendsStdClass();

foo->set('bar', 'baz');

echo foo->bar;

?>

but, the linter will not recognize props being set in this way, nor provide any type hinting:

Undefined property: extendsStdClass::$bar

Is there some reason we are not able to write to props on a class instance that is defined as a constant?


Solution

  • I'd like to be able to define this const in a namespace, and access/modify it via

    If you want to modify it, then it's not a const.

    If you actually want a const, then you can just use an array to get key/value pairs:

    namespace MyNamespace {
        const FOO = [
            'one' => 1,
            'two' => 2,
        ];
    }
    

    Then reference it anywhere via:

    print_r(\MyNamespace\FOO);
    

    Yields:

    Array
    (
        [one] => 1
        [two] => 2
    )
    

    And you can pull out a single value with array notation:

    echo \MyNamespace\FOO['one'];
    

    If you want something that you can reference directly by namespace, and still modify, you could create a class with static storage. Sort of like a half-assed singleton:

    namespace MyNamespace;
    
    class Foo
    {
        private static array $data = [];
        public static function get($name)
        {
            return self::$data[$name] ?? null;
        }
        public static function set($name, $value)
        {
            self::$data[$name] = $value;
        }
    }
    

    Then you can set values from anywhere:

    \MyNamespace\Foo::set('one', 1);
    

    And get values from anywhere:

    echo \MyNamespace\Foo::get('one');