How do I create a PHP static class property at runtime (dynamically)?

前端 未结 4 1895
遥遥无期
遥遥无期 2021-02-19 12:47

I\'d like to do something like this:

public static function createDynamic(){
    $mydynamicvar = \'module\'; 
    self::$mydynamicvar = $value;
}
相关标签:
4条回答
  • 2021-02-19 13:28

    Static properties must be defined in the class definition. Therefore, real static properties cannot be created dynamically like regular properties.

    For example, if you run this:

    <?php
    
    class MyClass
    {
        public static function createDynamic()
        {
            $mydynamicvar = 'module';
            self::$mydynamicvar = $value;
        }
    }
    
    MyClass::createDynamic();
    
    var_dump(MyClass::$mydynamicvar);
    var_dump(MyClass::$module);
    

    ...you'll get this error

    Fatal error: Access to undeclared static property: MyClass::$mydynamicvar test.php on line 8
    

    Notice how the error occurs on line 8 when trying to set the property instead of line 14 or 15 (as you might expect if you were simply doing it wrong and dynamically creating static properties was actually possible).

    0 讨论(0)
  • 2021-02-19 13:37

    I don't know exactly why you would want to do this, but this works. You have to access the dynamic 'variables' like a function because there is no __getStatic() magic method in PHP yet.

    class myclass{
        static $myvariablearray = array();
    
        public static function createDynamic($variable, $value){
            self::$myvariablearray[$variable] = $value;
        }
    
        public static function __callstatic($name, $arguments){
            return self::$myvariablearray[$name];
        }
    }
    
    myclass::createDynamic('module', 'test');
    echo myclass::module();
    
    0 讨论(0)
  • 2021-02-19 13:38

    static variables must be part of the class definition, so you can't create them dynamically. Not even with Reflection:

    chuck at manchuck dot com                                             2 years ago
    

    It is important to note that calling ReflectionClass::setStaticPropertyValue will not allow you to add new static properties to a class.

    But this looks very much like a XY Problem. You probably don't really want to add static properties to a PHP class at runtime; you have some use case that could be fulfilled also that way. Or that way would be the fastest way, were it available, to fulfill some use case. There well might be other ways.

    Actually the use cases below are yet again possible solutions to some higher level problem. It might be worth it to reexamine the high level problem and refactor/rethink it in different terms, maybe skipping the need of meddling with static properties altogether.

    I want a dictionary of properties inside my class.

    trait HasDictionary {
        private static $keyValueDictionary = [ ];
    
        public static function propget($name) {
            if (!array_key_exists($name, static::$keyValueDictionary) {
                return null;
            }
            return static::$keyValueDictionary[$name];
        }
    
        public static function propset($name, $value) {
            if (array_key_exists($name, static::$keyValueDictionary) {
                $prev = static::$keyValueDictionary[$name];
            } else {
                $prev = null;
            }
            static::$keyValueDictionary[$name] = $value;
            return $prev;
        }
    }
    
    
    class MyClass
    {
        use Traits\HasDictionary;
    
        ...$a = self::propget('something');
    
        self::propset('something', 'some value');
    }
    

    I want to associate some values to a class, or: I want a dictionary of properties inside some one else's class.

    This actually happened to me and I found this question while investigating ways of doing it. I needed to see, in point B of my workflow, in which point ("A") a given class had been defined, and by what other part of code. In the end I stored that information into an array fed by my autoloader, and ended up being able to also store the debug_backtrace() at the moment of class first loading.

    // Solution: store values somewhere else that you control.
    
    class ClassPropertySingletonMap {
        use Traits\HasDictionary; // same as before
    
        public static function setClassProp($className, $prop, $value) {
            return self::propset("{$className}::{$prop}", $value);
        }
    
        public static function getClassProp($className, $prop) {
            return self::propget("{$className}::{$prop}");
        }
    }
    
    // Instead of
    // $a = SomeClass::$someName;
    // SomeClass::$someName = $b;
    
    // we'll use
    // $a = ClassPropertySingletonMap::getClassProp('SomeClass','someName');
    // ClassPropertySingletonMap::setClassProp('SomeClass','someName', $b);
    

    I want to change, not create, an existing property of a class.

    // Use Reflection. The property is assumed private, for were it public
    // you could do it as Class::$property = $whatever;
    
    function setPrivateStaticProperty($class, $property, $value) {
        $reflector = new \ReflectionClass($class);
        $reflector->getProperty($property)->setAccessible(true);
        $reflector->setStaticPropertyValue($property, $value);
        $reflector->getProperty($property)->setAccessible(false);
    }
    
    0 讨论(0)
  • 2021-02-19 13:45

    A related problem that IS possible (in PHP 5.4.0 and up) is to include various separate groups of static variable or constant declarations and group them together into one class declaration.

    Here is an example:

    trait Added1 // This can be located in one Include file
        {
        static
        $x="hello"; // Can declare more variables here
        }
    trait Added2 // This can be located in another Include file
        {
        static
        $y="world"; // Can declare more variables here
        }
    class G // Global constant and variable declarations class
        {
        use Added1, Added2; // Combines all variable declarations
        }
    
    echo G::$x." ".G::$y; // Shows "hello world" on the web page
    
    0 讨论(0)
提交回复
热议问题