用于 PHP 中静态属性的魔术 __get getter

Posted

技术标签:

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

不起作用,即使它起作用了,碰巧我已经需要魔法 __get 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

以上是关于用于 PHP 中静态属性的魔术 __get getter的主要内容,如果未能解决你的问题,请参考以下文章

php魔术方法

php 中__set()和__get()的具体用法

PHP魔术法__set和__get

PHP中魔术方法详解

php魔术方法

php魔术方法