2010-10-28 22 views
0

J'ai essayé de trouver un moyen de renvoyer dynamiquement des valeurs de propriété pour une classe en utilisant __call au lieu de créer une série de fonctions dont le seul but serait de renvoyer ces valeurs. L'idée que j'ai est de pouvoir demander (par exemple) $ this-> fetch_PersonFirstName() et de vérifier si la classe $ this-> person ["first_name"] est définie et renvoie la valeur. Un autre exemple serait d'appeler $ this-> fetch_BookGenreTitle() et que la classe renvoie la valeur $ this-> book ["genre"] ["title"]. Je sais quelque chose comme ceci devrait faire un peu de vérification afin qu'il détermine automatiquement que, par exemple, puisque $ ce-> livre ["genre_title"] n'existe pas, alors il devrait vérifier $ this-> book ["genre"] ["title"]. Jusqu'ici je suis arrivé avec du code qui (pour une raison quelconque) fonctionne pour retourner les valeurs d'un tableau (comme mon exemple de personne) mais mon problème se développe rapidement quand j'essaye de retourner les valeurs d'un tableau multidimensionnel (comme avec mon exemple de livre ci-dessus). Je suis toujours en train d'essayer de trouver un moyen pour que la méthode __call vérifie l'existence d'une méthode, et si elle n'existe pas, alors l'autre.Comment utiliser __call pour renvoyer dynamiquement des valeurs de propriété

S'il vous plaît, jetez-moi une ligne ici. Je me suis cogné la tête contre le mur en essayant de comprendre ça et ça me tue.

<?php 

class Test 
{ 
    protected $person; 
    protected $book; 

    public function __construct() 
    { 
     $this->person["first_name"] = "John Smith"; 
     $this->book["genre"]["title"] = "Suspense"; 
    } 

    public function __call($method, $args) 
    { 
     $args = implode(", ", $args); 

     if (preg_match("/^fetch_([A-Z]{1,}[a-z]{1,})(.*)?/", $method, $match)) 
     { 
      print_r($match); 
      echo "<br><br>"; 
      $property = strtolower($match[1]); 
      $indexes = $match[2]; 

      if (property_exists("Test", $property)) 
      { 
       if ($indexes) 
       { 
        $indexes = preg_split("/(?<=[a-z])(?=[A-Z])/", $indexes); 

        $num_indexes = count($indexes); 
        $count_indexes = 1; 

        for ($count=0; $count<$num_indexes; $count++) 
        { 
         $record  = strtolower($indexes[$count]); 
         $index .= $record; 
         $array .= "{$record}"; 

         $var_index = $index; 
         $var_array = $array; 

         echo $var_index." {$count}<br>"; 
         echo $var_array." {$count}<br>"; 
         //print_r($this->{$property}{$var_array}); 

         if ($count_indexes == $num_indexes) 
         { 
          if (isset($this->{$property}{$var_index})) 
          { 
           return $this->{$property}{$var_index}; 
          } 
          else 
          { 
           return $this->{$property}{$var_array}; 
          } 
         } 
         else 
         { 
          $index .= "_"; 
         } 

         $count_indexes++; 
        } 
        echo "<br><br>"; 
       } 
       else 
       { 
        return $this->{$property}; 
       } 
      } 
     } 
    } 
} 
?> 

<?php 


    $test = new Test(); 
    echo $test->fetch_PersonFirstName(); 
    echo "<br><br>"; 
    echo $test->fetch_BookGenreTitle(); 
?> 
+3

ne soyez pas paresseux. Ajoutez les Getters dont vous avez besoin au lieu d'encourir la pénalité de performance de __call, et encore moins celle qui fait autant de travail. – Gordon

Répondre

0

Compte tenu "BookGenreTitle":

  1. utiliser une sorte de regex séparer "Livre", "Genre" et "Titre"
  2. property_exists($this, "Book")
  3. array_key_exists("genre", $this->book)
  4. Si la clé existe, le retour $this->book["genre"]
  5. Si la clé n'existe pas, array_key_exists("genre_title", $this->book)
  6. Si la clé existe, renvoyer $this->book["genre_title"]
  7. Si la clé n'existe pas, array_key_exists("genre", $this->book) && array_key_exists("title", $this->book["genre"])
  8. continuer à aller

Il y a probablement un moyen d'utiliser une boucle ou une sorte de récursion au lieu de coder en dur la profondeur maximale, mais je ne entrer dans ce maintenant ...

Oh, et comme l'autre affiche a dit, ce que vous voulez est la surcharge de la propriété (__get et __set).

+0

Je vois ce que vous voulez dire dans votre exemple. Donc, au lieu de demander $ this-> fetch_BookGenreTitle() et la méthode __call, je demanderais $ this-> fetch_BookGenreTitle en tant que propriété et utiliser la méthode __get, n'est-ce pas? – waywardspooky

+0

@waywardspooky Oui, exactement. Vous ne savez pas quelle différence de performance cela ferait (tout est magique de toute façon) mais il n'y a aucune raison d'utiliser des méthodes à moins de devoir passer des arguments. Oh, et laissez tomber le préfixe 'fetch_', c'est moche et inutile. – kijin

0

Vous devez jeter un oeil à property overloading, pas method overloading que vous avez déjà compris dans le titre de la question vous-même.

+0

Merci. J'avais expérimenté avec __set et __get il y a quelques temps mais pour une raison ou une autre, il ne m'est pas venu à l'idée de suivre cette voie. – waywardspooky

1

Merci encore les gens.Je pense que j'ai enfin ma solution, qui fonctionne pour les tableaux multidimensionnels ou toute profondeur et les comptes pour déterminer si une propriété est, par exemple $ this-> book ["genre_title"] ou $ this-> book ["genre" ] [ « title »] :)

Je poste le code ci-dessous comme quelqu'un d'autre peut trouver au hasard utile dans l'avenir

<?php 

class Test 
{ 
    protected $person; 
    protected $book; 

    public function __construct() 
    { 
     $this->person["first_name"] = "John Smith"; 
     $this->book["genre"]["title"] = "Suspense"; 
    } 

    public function __get($var) 
    { 
     if (preg_match_all("/([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)/", $var, $matches)) 
     { 
      $matches  = $matches[1]; 
      $property  = strtolower($matches[0]); 

      if (property_exists($this, $property)) 
      { 
       unset($matches[0]); 

       $matches  = array_values($matches); 
       $num_matches = count($matches); 

       $var = &$this->{$property}; 

       if (!$num_matches) 
       { 
        return $var; 
       } 
       else 
       { 
        foreach($matches as &$match) 
        { 
         $match = strtolower($match); 
         $index .= $match; 

         if ($probe = $this->iterateArray($var, $index)) 
         { 
          $var = $probe; 
          unset($index); 
         } 
         elseif ($probe = $this->iterateArray($var, $index)) 
         { 
          $var = $probe; 
         } 
         else 
         { 
          $index .= "_"; 
         } 
        } 

        return $var; 
       } 
      } 
     } 
    } 

    public function iterateArray($var, $index) 
    { 
     if (array_key_exists($index, $var)) 
     { 
      return $var[$index]; 
     } 
     else 
     { 
      return false; 
     } 
    } 
} 
?> 

<?php 


    $test = new Test(); 
    echo $test->PersonFirstName; 
    echo "<br><br>"; 
    echo $test->BookGenreTitle; 
?> 

il est plus que probable des façons d'améliorer/rationaliser le code , auquel cas toute personne souhaitant le faire est plus que bienvenue pour poster une version améliorée.