GETTER

ViPHP
AB
ViPHP | 5818 Messages

26 août 2010, 18:20

Instinctivement, j'aurai utiliser un switch/cases
...
Mais la solution du tableau me va aussi ;)
L'avantage du tableau c'est qu'il peut être construit dynamiquement, qu'il peut être facilement passé en paramètre etc. :)

ViPHP
ViPHP | 5462 Messages

26 août 2010, 18:32

mais au-faite, pourquoi ne pas utilisé public pour certain et private pour d'autre ?

ps : avec PDO tu peux direct faire un fetch dans la class
$resultat  = $result->fetch(PDO::FETCH_INTO, $this);

Mammouth du PHP | 19672 Messages

26 août 2010, 18:47

mais au-faite, pourquoi ne pas utilisé public pour certain et private pour d'autre ?

ps : avec PDO tu peux direct faire un fetch dans la class
$resultat  = $result->fetch(PDO::FETCH_INTO, $this);
Rhaaaaaaa que voilà la bonne question que j'attendais impatiemment :)

Suppose un instant que tu aies une base de données avec quelques tables. Crées un petit fichier de conf avec dedans un tableau associatif à deux niveaux : premier niveau, le nom des tables, second niveau, le nom des colonnes de chaque table. Dans une classe un poil plus générique d'accès à tes données, tu inclus ce fichier et lors de la création de l'instance, tu précises en paramètre le nom de la table : du coup, je te laisse y réfléchir un moment, mais pense aux possibilités qui s'ouvrent avec la méthode que j'ai suggéré ;)

À titre indicatif, je me suis construit un package d'accès aux données basé sur ce système : que mes bases de données aient 3 tables ou 5000, pour moi c'est pareil, je n'utilise qu'une seule classe pour manipuler mes champs de table. Bon il va de soi que je me suis construit un script spécifique pour construire mon fichier de configuration, mais je n'ai pas besoin de créer une classe par table. Une modification dans mon schéma de données ? pas de soucis, je répercute ça... dans le fichier de configuration sans toucher à ma classe :)

Or, pour en revenir à cette question : tout simplement parce que les propriétés sont définies dynamiquement : dans le code lui-même, elles n'existent pas du tout, on ne peut donc pas leur affecter de niveau de visibilité.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

ViPHP
ViPHP | 5462 Messages

26 août 2010, 19:05

oui, et malheureusement la readonly ne marche que pour les extensions

ViPHP
ViPHP | 5462 Messages

28 sept. 2010, 18:39

Suppose un instant que tu aies une base de données avec quelques tables. Crées un petit fichier de conf avec dedans un tableau associatif à deux niveaux : premier niveau, le nom des tables, second niveau, le nom des colonnes de chaque table. Dans une classe un poil plus générique d'accès à tes données, tu inclus ce fichier et lors de la création de l'instance, tu précises en paramètre le nom de la table : du coup, je te laisse y réfléchir un moment, mais pense aux possibilités qui s'ouvrent avec la méthode que j'ai suggéré ;)
en relisant ca je vois pas trop, ta un exemple simple faille qu'on pourrait faire ?

Mammouth du PHP | 19672 Messages

28 sept. 2010, 19:27

Ok, alors petit exemple vraiment basique, j'ai fait ça en quelques minutes pour les besoin de l'exemple, mon propre système est trop complexe pour être expliqué rapidement.

D'abord un fichier de configuration, tout ce qu'il y a de simple :
<?php
/**
 * Fichier de configuration.
 * 
 * Description du modèle de données
 */
$dbConf = array(
    'personnes_per' => array(
        'per_id',
        'per_nom',
        'per_prenom'
    ),
    'telephones_tel' => array(
        'tel_id',
        'per_id',
        'tel_numero',
        'tel_type'
    )
);
?>
Jusque là, rien de sorcier, on crée un mini annuaire, ma base de données a deux tables, une pour lister le nom des personnes et la seconde pour enregistrer leurs différents numéros de téléphone, que ce soit des fixe ou des portable voire pourquoi pas des fax.

La classe maintenant avec mes Getter/Setter magiques, suis les commentaires, ils devraient être suffisamment explicites :
<?php
/**
 * Classe permettant l'accès à n'importe quelle table indiquée
 * dans un tableau de configuration.
 */
class accesTable
{
    /**
     * Nom de la table à laquelle on accède.
     *
     * @var String
     */
    private $_nomTable;
    /**
     * Description des collones de la table instanciée.
     *
     * @var Array
     */
    private $_conf;
    
    /**
     * Constructeur.
     * 
     * Définit le nom de la table qu'on veut consulter en
     * initialisant son nom et la liste de ses collones.
     *
     * @param String    $nomTable
     * @param Array     $conf
     */
    public function __construct($nomTable, $conf)
    {
        /* On initialise la configuration */
        $this->_nomTable    = $nomTable;
        $this->_conf        = $conf[$nomTable];
        /**
         * On lance la construction de la table en déterminant quelles 
         * colonne on peut utiliser.
         */
        $this->_init();
    }
    
    /**
     * Setter magique.
     * 
     * Assigne une valeur à une collone à condition que celle-ci 
     * existe dans la configuration.
     *
     * @param   String      $colonne    Nom de la colonne
     * @param   String      $valeur     Valeur à affecter à la colonne
     * @throws  Exception               Si la colonne n'existe pas dans la table, on lève une exception
     */
    public function __set($colonne, $valeur)
    {
        if(in_array($colonne, $this->_conf))
        {
            $this->{$colonne} = $valeur;
        }
        else
        {
            throw new Exception("La collone ". $colonne ." n'existe pas dans la table ". $this->_nomTable, E_USER_WARNING);
        }
    }

    /**
     * Getter magique.
     * 
     * Vérifie l'existence de la colonne dans la table et en retourne la
     * valeur courante si elle a été assignée.
     *
     * @param   String $colonne         Nom de la colonne
     * @return  String
     * @throws  Exception               Si la colonne n'existe pas dans la table, on lève une exception
     */
    public function __get($colonne)
    {
        if(in_array($colonne, $this->_conf))
        {
            return($this->{$colonne});
        }
        else
        {
            throw new Exception("La collone ". $colonne ." n'existe pas dans la table ". $this->_nomTable, E_USER_WARNING);
        }
    }

    /**
     * Initialisation des propriétés dynamiques de l'instance.
     * 
     * Pour la table définie dans le constructeur, on crée une propriété
     * dynamiquement pour chaque colonne existant dans la configuration de 
     * la table. La méthode est privée et déclenchée par le constructeur.
     */
    private function _init()
    {
        foreach($this->_conf as $collone)
        {
            $this->{$collone} = null;
        }
    }
}
Si ça va toujours, note quand même qu'il manque des méthodes, en particulier la connexion et les méthodes d'accès à la base, mais l'idée de base, c'est une unique classe pour n'importe quel nombre de tables.

Comment utiliser ça :
<?php
/**
 * On veut créer une nouvelle ligne dans la table personne par exemple :
 */
$oPersonne = new accesTable('personne_per', $dbConf['personne_per']);
/* On va maintenant enregistrer des valeurs */
$oPersonne->per_nom    = 'Tartempion';
$oPersonne->per_prenom = 'Julot';
/* On tente d'alimenter une propriété inexistante  */
$oPersonne->qualite    = 'caractériel';
Et de fait, la dernière tentative d'utilisation du set magique me retourne une exception définie dans le __set() puisque per_qualite n'est pas une colonne de la table personne_per.

Tu peux maintenant imaginer un système pour ajouter une méthode save(), ou encore pour effectuer d'autres opérations, tu pourrais peaufiner le tableau de configuration en indiquant les types, les longueurs, les colonnes autorisant les valeurs NULL, etc... et bien entendu il faudrait dans ce cas adapter les méthodes à partir des informations dont tu disposes.

Est-ce que c'est plus clair comme ça ?
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

ViPHP
ViPHP | 5462 Messages

28 sept. 2010, 20:37

je comprend, mais lui c'est pas dynamique son code.

Mammouth du PHP | 661 Messages

28 sept. 2010, 20:51

$oPersonne = new accesTable('personne_per', $dbConf['personne_per']);
Heuu .. t'es sur de ton coup !?? :shock:
ça rentre pas en contradiction avec :
      $this->_conf        = $conf[$nomTable];
:twisted:

En tout cas, ça me confirme que ce que j’envisageais n'est pas une si mauvaise idée !... le seul truc Vraiment Chiant avec ça (à ce que j'imagine actuellement) c'est quand tu as plus de 150 tables et que toutes sont liées entre elles !... mais qd je me collerais au sujet, je saurais venir te chercher ;)
Modifié en dernier par Nours312 le 28 sept. 2010, 20:53, modifié 1 fois.

ViPHP
ViPHP | 5462 Messages

28 sept. 2010, 20:52

c'était pour l'exemple :wink:

Mammouth du PHP | 661 Messages

28 sept. 2010, 20:54

c'était pour l'exemple :wink:
Ouais, mais vu qu'il ne fait que très rarement des fautes d’inattention, il faut le signaler ! :P

Mammouth du PHP | 19672 Messages

28 sept. 2010, 21:58

$oPersonne = new accesTable('personne_per', $dbConf['personne_per']);
Heuu .. t'es sur de ton coup !?? :shock:
ça rentre pas en contradiction avec :
      $this->_conf        = $conf[$nomTable];
Tu as raison effectivement, j'ai modifié en dernière seconde en oubliant ce détail et en réalité, ça aurait du être :
      $this->_conf        = $conf;
Et là, ça doit fonctionner.

Ceci étant, je suis effectivement certain que ça fonctionne, je l'utilise tous les jours avec un système un poil plus élaboré et comme je l'ai mentionné plus tôt, que j'aie 2 tables ou 5000, ça ne me fait ni chaud ni froid, je ne crée pas davantage de classes. Et en fait, mon tableau de configuration ressemble, je m'en suis rendu compte il n'y a pas très longtemps, à un fichier de configuration Propel ou Doctrine, je sais plus lequel des deux. La différence principale est qu'au lieu d'être en YAML ou autre langage qu'il faudrait parser et interpréter avant utilisation, c'est directement du PHP. J'ai pas mal d'informations dedans incluant les relations, les types de tables si elles sont relationnelles ou non, ainsi que les vues mais ça, c'est en prévision d'une évolution ultérieure.

À ce stade, je construis moi-même les requêtes SQL mais ça risque de rester comme ça pas mal de temps, je me refuse à construire une usine à gaz pour tenter d'automatiser le système, j'ai déjà tenté une approche, sur certaines structures simple ça pourrait plus ou moins fonctionner, mais sur des systèmes importants, ça va être une catastrophe. Mais en marge de ça, j'ai un certain nombre de classes pour simplifier au maximum l'utilisation.

Je suis parti sur un principe de base essentiel : en lecture, je vais m'attaquer à un nombre de table de 1 à n, mais en écriture, je n'écris jamais que sur une seule table à la fois. Or les système à la manière Zend Framework où on écrit une classe par table, ça me fatigue d'avance. La moindre modification et je dois aller modifier la ou les classes correspondantes. Là, je ne touche qu'au fichier de configuration que je régénère avec le script approprié. Pour l'instant, ça ne fonctionne qu'avec MySQL, mais il est prévu de l'étendre pour d'autres SGBD, que ce soit Oracle ou autre. Et pour ce qui est des requêtes, je passe par PDO, donc pas de soucis, si le pilote existe pour un SGBD, le système pourra le prendre en charge.

Voilà, pour l'instant, ceci dit il me reste à finir de stabiliser quelques détails et à faire un peu de ménage dans le code avant d'envisager une quelconque publication. Mais je vous garantis que ça fonctionne fort bien.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

devlop78
Invité n'ayant pas de compte PHPfrance

29 oct. 2010, 18:31

tu les met en public

public $pseudo;

tu y accède comme ca après

$user->pseudo


tu pourrais faire un surcharge avec __call si tu tiens a garder la forme getMachin() :wink:
Stealth, c'est indigne de toi :lol:

Perso, je mets maintenant toutes mes propriétés en private ou proteged, et j'y accède avec des accesseurs et mutateurs.

private $machin;

public function setMachin ($var) { if (!is_int($var)) throw new Exception ("integer waited"); $this->machin = $var; }

Et comme je suis un gros flemmard:

function __call ($method, $args) { if (substr($method,3) == "set") ... }

Par contre, le __cal possède un gros désaventage sous éclipse ... mais il serait capable de générer automatiquement les accesseurs ... alors ...

ViPHP
ViPHP | 5462 Messages

29 oct. 2010, 18:48

je fais pas de get/setMachin, j'utilise que public, comme ca je suis pas embêtes avec les FETCH_CLASS, les sérialise, __set_state et compagnie, je parle bien sur des classe models (d'ailleurs je m'en occupe pu c'est doctrine que le fais :mrgreen: )

ViPHP
ViPHP | 2577 Messages

05 nov. 2010, 12:44

Bonjour,

En ayant découvert les __get, __set et __call récemment, j'en suis venu à mettre mes propriétés publics dans un tableau associatif.

j'utilise alors $o->variable à droite ou à gauche d'un =. Cela déclenche le __get ou le __set dans lequel j'appelle set_variable ou get_variable. Je trouve l'écriture plus simple.

En cas de traitement particulier défini, il s'exécute et sinon il passe la main à __call dans lequel j'affecte ou retourne $this->xxx['variable'].

Dans le cadre d'un maquettage, ca me semble très bien, par contre, je pense supprimer le __call en production et codant tous les setter et getter. Par contre, je garderai le principe des __set et __get pour l'écriture agréable du code.