2009-02-10 7 views
12

Comment puis-je faire en PHPComment faire une classe imbriquée PHP ou des méthodes imbriquées?

$myDBClass->users()->limit(5);//output you limited users to 5 
$myDBClass->comments()->limit(3);//output you limited comments to 3 

ce que je voulais dire est des méthodes imbriquées ou classe imbriquée (je ne sais pas!) quand j'appelle la méthode limite comme un enfant des utilisateurs, il saura que Je l'appelle de la méthode "users" -ou de la classe- et quand j'appelle la méthode limite -ou la classe! - des commentaires Il le sait aussi.

Quelle est la structure possible pour une classe PHP pour faire cette chose?


la raison de cette question parce que je travaille sur ma propre classe pour la base de données afin que je puisse facilement utiliser quelque chose comme ça

 $DB->comments()->id(" > 3")->limit(10); 

pour générer le code sql « select * from commentaires où id> 3 limite 10 " Merci

+4

**, ne pas nicher. – Pacerier

Répondre

17

Les méthodes renvoient des objets avec les méthodes décrites, et vous obtenez ce que vous recherchez. Donc, tant que $DB est un objet qui a une méthode comments(), cette partie est valide. Si comments() renvoie un objet qui a une méthode id(), cette partie est également valide. Ensuite, id() doit retourner un objet qui a la limit() -method.

Dans votre cas, vous voudrez peut-être faire quelque chose comme ceci:

class DB { 
    public function comments() { 
    // do preparations that make the object select the "comments"-table... 
    return $this; 
    } 

    public function id($string) { 
    // handle this too... 
    return $this; 
    } 

    public function limit($int) { 
    // also this 
    return $this; 
    } 

    public function execute() { 
    $success = try_to_execute_accumulated_db_commands(); 
    return $success; 
    } 
} 

$DB = new DB(); 

Dans mon exemple, chaque méthode (également non représenté ici) retourne l'objet lui-même, de sorte que les commandes peuvent être enchaînées . Lorsque la construction de la requête de base de données est terminée, vous évaluez réellement la requête en appelant execute() qui (dans mon cas) renverrait un booléen qui représenterait le succès de l'exécution de la base de données.

L'utilisateur nickohm a suggéré que cela s'appelle un fluent interface. Je dois admettre que c'est un nouveau terme pour moi, mais cela dit probablement plus de mes connaissances, que l'utilisation du terme. ("Je viens d'écrire un code, vous savez ...")

Note:$this est une variable 'magique' qui pointe vers l'objet actuellement actif. Comme son nom l'indique, il se présente lui-même comme la valeur de retour de la méthode.

+0

Bon exemple. J'étais sur le point de poster quelque chose exactement pareil. Peut-être que vous voulez parler de ce que l'on appelle une interface fluide: http://en.wikipedia.org/wiki/Fluent_interface – nickohrn

+0

Ceci est utilisé dans ExtPHP http://nexus.zteo.com/2008/03/04/extphp-an extjs-converterwrapper-for-php-developers / – Seiti

9

La convention standard pour cela est de renvoyer l'instance de $ this à la fin de chaque appel de méthode. Ainsi, lorsque nous revenons à l'appelant, nous faisons simplement référence à un autre appel de méthode.

class Foo 
{ 
    public function do_something() 
    { 
    return $this; 
    } 

public function do_something_else() 
{ 
    return $this; 
    } 
} 

$foo->do_something()->do_something_else(); 
0

Un simple à mettre en œuvre la méthode pour démarrer pourrait aller comme:

class db 
{ 
    public function __call($function, $arguments) 
    { 
    switch($function) { 
     // implement table handling here 
     case 'user': 
     //do something 
     return $something; 
     break; 
    } 
    } 
} 

Selon vous voulez aller compliqué, mais solide ou simple, mais moins souple vous pourriez ou non mettre en œuvre deux stratégies différentes. stratégie simple pourrait aller comme ceci:

class db 
{ 

    protected $operatingTable; 

    public function limit($limitNumber) 
    { 
    return $this->executeQuery("SELECT * FROM ".$this->operatingTable." LIMIT ".$limitNumber); // where executeQuery is a function that runs a query 
    } 

    public function __call($function, $arguments) 
    { 
    switch($function) { 
     // implement table handling here 
     case 'user': 
     $this->operatingTable='user'; // alternately, but less secure: $this->operatingTable=$function; 
     return $this; 
     break; 
    } 
    } 
} 

Alternativement, mais plus puissant:

class db 
{ 
    protected $operatingTable; 

    public function limit($limitNumber) 
    { 
    return $this->executeQuery("SELECT * FROM ".$this->operatingTable." LIMIT ".$limitNumber); // where executeQuery is a function that runs a query 
    } 

    public function __call($function, $arguments) 
    { 
    switch($function) { 
     // implement table handling here 
     case 'user': 
     $user = new user($this); // pass in the database to the object, so the table object can have a reference to the db 
     return $user; 
     break; 
    } 
    } 
} 

class baseTableClass 
{ 
    protected $db; // an instance of class db 

    function limit($limitNumber) 
    { 
    $db->execute($aStatementDerivedFromThisClassesInformation); // execute a sql command, based on information about the table in the class 
    } 

} 

class user extends baseTableClass 
{ 
    public function __construct($db) { 
    $this->db = $db; 
    } 
} 

Vous avez l'idée. Soit surcharger l'objet db, soit créer un objet db de base et des objets table, en mettant une grande partie de l'intelligence dans les objets table, en veillant à ce qu'un objet table stocke une référence à l'objet db

Questions connexes