【问题标题】:Magic __get getter for static properties in PHP用于 PHP 中静态属性的魔术 __get getter
【发布时间】:2010-11-19 17:54:16
【问题描述】:
public static function __get($value)

不起作用,即使它起作用了,碰巧我已经需要魔法 __get getter 来获取同一类中的实例属性。

这可能是一个是或否的问题,所以,有可能吗?

【问题讨论】:

    标签: php oop properties getter


    【解决方案1】:

    结合 __callStaticcall_user_funccall_user_func_array 可以访问 PHP 类中的静态属性

    例子:

    class myClass {
    
        private static $instance;
    
        public function __construct() {
    
            if (!self::$instance) {
                self::$instance = $this;
            }
    
            return self::$instance;
        }
    
        public static function __callStatic($method, $args) {
    
            if (!self::$instance) {
                new self();
            }
    
            if (substr($method, 0, 1) == '$') {
                $method = substr($method, 1);
            }
    
            if ($method == 'instance') {
                return self::$instance;
            } elseif ($method == 'not_exist') {
                echo "Not implemented\n";
            }
        }
    
        public function myFunc() {
            echo "myFunc()\n";
        }
    
    }
    
    // Getting $instance
    $instance = call_user_func('myClass::$instance');
    $instance->myFunc();
    
    // Access to undeclared
    call_user_func('myClass::$not_exist');
    

    【讨论】:

      【解决方案2】:

      此外,您可以使用 __get() 获取静态属性,就像成员属性一样访问它们:

      class ClassName {    
          private static $data = 'smth';
      
          function __get($field){
              if (isset($this->$field)){
                  return $this->$field;
              }
              if(isset(self::$$field)){  
                  return self::$$field;  // here you can get value of static property
              }
              return NULL;
          }
      }
      
      $obj = new ClassName();
      echo $obj->data; // "smth"
      

      【讨论】:

      • 除了它现在是公开的,所以你甚至不需要__get
      • isset 如果字段存在但设置为 null,则返回 false。更好地使用 property_exists
      • @RudigerW。好点子。我还建议在找不到匹配属性时抛出异常而不是return null,以遵循没有魔法吸气剂会发生的行为。 @JeffPuckett - 我编辑了答案以澄清:)
      【解决方案3】:

      试试这个:

      class nameClass{
          private static $_sData = [];
          private static $object = null;
          private $_oData = [];
      
          public function __construct($data=[]){
              $this->_oData = $data;
          }
      
          public static function setData($data=[]){
              self::$_sData = $data;
          }
      
          public static function Data(){
              if( empty( self::$object ) ){
                  self::$object = new self( self::$_sData ); 
              }
              return self::$object;
          }
      
          public function __get($key) {
              if( isset($this->_oData[$key] ){
                  return $this->_oData[$key];
              }
          }
      
          public function __set($key, $value) {
              $this->_oData[$key] = $value;
          }
      }
      
      nameClass::setData([
          'data1'=>'val1',
          'data2'=>'val2',
          'data3'=>'val3',
          'datan'=>'valn'
      ]);
      
      nameClass::Data()->data1 = 'newValue';
      echo(nameClass::Data()->data1);
      echo(nameClass::Data()->data2);
      

      【讨论】:

        【解决方案4】:

        非常好的 mbrzuchalski。但它似乎只适用于公共变量。只需将您的开关更改为此以允许它访问私有/受保护的:

        switch($match[1]) {
           case 'get': return self::${$property->name};
           case 'set': return self::${$property->name} = $args[0];
        }
        

        您可能希望更改 if 语句以限制可访问的变量,否则会破坏将它们设为私有或受保护的目的。

        if ($reflector->hasProperty($property) && in_array($property, array("allowedBVariable1", "allowedVariable2"))) {...)
        

        例如,我有一个类旨在使用 ssh pear 模块为我从远程服务器中提取各种数据,并且我希望它根据要求查看的服务器对目标目录做出某些假设在。 mbrzuchalski 方法的调整版本非常适合。

        static public function __callStatic($method, $args) {
            if (preg_match('/^([gs]et)([A-Z])(.*)$/', $method, $match)) {
                $reflector = new \ReflectionClass(__CLASS__);
                $property = strtolower($match[2]). $match[3];
                if ($reflector->hasProperty($property)) {
                    if ($property == "server") {
                        $property = $reflector->getProperty($property);
                        switch($match[1]) {
                            case 'set':
                                self::${$property->name} = $args[0];
                                if ($args[0] == "server1") self::$targetDir = "/mnt/source/";
                                elseif($args[0] == "server2") self::$targetDir = "/source/";
                                else self::$targetDir = "/";
                            case 'get': return self::${$property->name};
                        }
                    } else throw new InvalidArgumentException("Property {$property} is not publicly accessible.");
                } else throw new InvalidArgumentException("Property {$property} doesn't exist.");
            }
        }
        

        【讨论】:

          【解决方案5】:

          也许有人还需要这个:

          static public function __callStatic($method, $args) {
          
            if (preg_match('/^([gs]et)([A-Z])(.*)$/', $method, $match)) {
              $reflector = new \ReflectionClass(__CLASS__);
              $property = strtolower($match[2]). $match[3];
              if ($reflector->hasProperty($property)) {
                $property = $reflector->getProperty($property);
                switch($match[1]) {
                  case 'get': return $property->getValue();
                  case 'set': return $property->setValue($args[0]);
                }     
              } else throw new InvalidArgumentException("Property {$property} doesn't exist");
            }
          }
          

          【讨论】:

          • 这是做什么的?
          • @starbeamrainbowlabs co:提取静态属性名称并尝试根据操作获取或设置它。
          • 由于对此答案缺乏评论:这需要致电Foo::getProp()/Foo::setProp() 才能工作。这与 OP 要求的不同,即能够编写 Foo::$prop 并调用魔法。
          【解决方案6】:

          不,这是不可能的。

          引用manual page of __get

          成员重载仅适用于 对象上下文。这些神奇的方法 不会在静态中触发 语境。因此这些方法可以 不能声明为静态的。


          在 PHP 5.3 中,添加了 __callStatic ;但是还没有__getStatic 也没有__setStatic;即使拥有/编码它们的想法经常出现在 php internals@ mailling-list 上。

          甚至还有Request for Comments: Static classes for PHP
          但是,仍然没有实现(还?)

          【讨论】:

          • @webarto 同意,但考虑到我们在 PHP 领域,它们是一流的 OOP 功能哈哈
          • @DejanMarjanovic 他们有自己的用例。
          • 链接好像坏了,页面在这里:wiki.php.net/rfc/static-classes
          猜你喜欢
          • 1970-01-01
          • 2011-06-10
          • 2010-12-26
          • 2012-04-05
          • 2011-04-26
          • 1970-01-01
          • 2015-07-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多