getters et setters php avec des traits

Les getters et setters en php donnent :

class test  {
    private $color='aa9900';

    public function getColor(){
        return $this->color;
    }
    public function setColor($value){
        $this->color=$value;
        return $this;
    }
}

la propriété est en privé et l’accesseur et modificateur sont en public !

Mon cahier des charges est très original :), (voir la rfc) je désire une propriété publique qui va utilisé en fait les getters et setters eux en mode privé : il est plus beau d’écrire :

$test=new test();
echo 'color:'.$test->color';
$test->color="bb0077";
echo 'color:'.$test->color';

et l’autocomplétion de mon IDE sera parfaite. On trouve pas mal d’exemple dans le manuel php. La, les traits sont parfaits pour cette tâche car il s’agit bien d’ajouter une fonctionnalité qui n’a rien a voir avec l’héritage métier de ma classe. En plus il faut bien trouver une bonne excuse pour faire mumuse avec les traits :)

On passe au code du trait :

Que fait mon trait properties ? Dans le constructeur, le trait recherche les getters et si ils existent, la propriété est alors déplacée en privé. Les méthodes magiques __set et __get seront utilisées pour faire appel automatiquement aux setters et getters.

trait properties {
    private $_=null;

    public function __construct(){
        self::constructor(); // call si constructeur dans la class parent
    }    
    public function constructor(){
        var_dump($this); // structure avant
        $this->_= new stdClass;
        foreach(/*get_object_vars*/($this) as $prop=>$value){
            $get=$this->_toGetter($prop);
            if (method_exists($this,$get)) {
                $this->_->$prop = $value ? $value : null;
                unset($this->$prop);   
            }
        }
        var_dump($this); // structure après !
    }

    public function __get ( $prop ){
        $get=$this->_toGetter($prop);
        if (method_exists($this,$get)) return $this->$get();
    }
    public function  __set ( $prop , $value ){
        $get=$this->_toGetter($prop);
        if (method_exists($this,$get)) {
            //echo '<br>__set:'.$prop.' - '.$value;
            $set=$this->_toSetter($prop);
            if (method_exists($this,$set))
                $this->$set($value);
            else
                {
                    throw new Exception('propriété '.$prop.' en lecture seule');
                }
        }
        else {
            $this->$prop=$value;
        }

    }

    private function _toGetter($prop){
        return 'get'.ucfirst($prop);
    }
    private function _toSetter($prop){
        return 'set'.ucfirst($prop);
    }
    protected function _set($prop,$value){
        $this->_->$prop=$value;
    }
    protected function _get($prop){
        return $this->_->$prop;
    }    

    public function _isset( $prop ){
        $get=$this->_toGetter($prop);
        return (method_exists($this,$get));
    }
}

Le constructeur du trait : est uniquement appelé si aucun constructeur n’existe pour la classe utilisant ce trait. Il est impossible dans le constructeur de la classe « utilisatrice » d’écrire : TraitNom::__construct() j’ai du donc écrit une méthode constructor.

Autre point désagréable, le trait est au même niveau que la classe l’utilisant : toutes les propriétés et méthodes privées sont accessibles dans les deux sens. Que le trait puisse avoir accès aux données privées de la classe me dérange fortement mais c’est bien sur logique puisque les deux classes fusionnent.

On passe a ma classe utilisatrice :

class test  {
    use properties {  }
    public $color='aa9900';
    private $couleurSoleil='000';

    private function getColor(){
        return $this->_get('color');
    }
    private function setColor($value){
        return $this->_set('color',$value);
    }

    private function getCouleurSoleil(){
        return $this->_get('couleurSoleil');
    }    

    public function __construct(){
        self::constructor();
        // plante properties::__construct() ; !!!
    }

}

Une propriété en lecture-écriture(color) et une autre en lecture seule.(couleursoleil).

L’appel a self::constructor(); n’est pas obligatoire : si il n’y a aucun constructeur dans la classe utilisatrice alors le constructeur du trait est appelé implicitement.
ici, $couleurSoleil est en private ! c’était juste pour tester que le trait a bien accès a tout.

L’utilisation :

<?php
$test=new test();

echo '<br />color:'.$test->color. ' ';

echo '<br />couleurSoleil: '.$test->couleurSoleil;
$test->color="bb0077";
echo '<br />color:'.$test->color. ' ';
$test->essai=1;

var_dump($test);
try{
$test->couleurSoleil="bb0077";
} catch (Exception $e) {
echo '<h4>'.$e->getMessage().'</h4>';
}

On utilise bien les propriétés et non les getters et setters

Share Button

Vous devriez aimer...