web-dev-qa-db-fra.com

Magic __get getter pour les propriétés statiques dans PHP

public static function __get($value)

ne fonctionne pas, et même si c'est le cas, il se trouve que j'ai déjà besoin du getter magique __get pour les propriétés d'instance dans la même classe.

C'est probablement une question oui ou non, alors, c'est possible?

58
treznik

Non ce n'est pas possible.

Citant le page de manuel de __get :

La surcharge des membres ne fonctionne que dans le contexte de l'objet. Ces méthodes magiques ne seront pas déclenchées dans un contexte statique. Par conséquent, ces méthodes ne peuvent pas être déclarées statiques.


Dans PHP 5.3, __callStatic a été ajouté; mais il n'y a pas __getStatic ni __setStatic encore ; même si l'idée de les avoir/les coder revient souvent sur php internals @ mailling-list.

Il y a même un Request for Comments: Static classes for PHP
Mais, toujours pas implémenté (encore?)

61
Pascal MARTIN

Peut-être que quelqu'un a encore besoin de ça:

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");
  }
}
16
mbrzuchalski

Très beau mbrzuchalski. Mais cela ne semble fonctionner que sur des variables publiques. Modifiez simplement votre commutateur sur celui-ci pour lui permettre d'accéder à ceux privés/protégés:

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

Et vous voudrez probablement changer l'instruction if pour limiter les variables qui sont accessibles, sinon cela irait à l'encontre du but de les avoir privées ou protégées.

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

Ainsi, par exemple, j'ai une classe conçue pour extraire pour moi diverses données d'un serveur distant à l'aide d'un module ssh pear, et je veux qu'il fasse certaines hypothèses sur le répertoire cible en fonction du serveur qu'il est invité à consulter. Une version modifiée de la méthode de mbrzuchalski est parfaite pour cela.

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.");
    }
}
4
Claymore

essaye ça:

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);
0
Gilberto

Combiner __callStatic et call_user_func ou call_user_func_array peut donner accès aux propriétés statiques dans la classe PHP

Exemple:

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');
0
Jonny

De plus, vous pouvez obtenir des propriétés statiques y accédant comme les propriétés des membres, en utilisant __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"
0
Jokerius