2010-10-28 3 views
0

Я пытался придумать способ динамического возврата значений свойств для класса с использованием __call вместо создания множества функций, единственной целью которых было бы вернуть эти значения. Идея, которую я имею, заключается в том, чтобы иметь возможность запросить (например) $ this-> fetch_PersonFirstName() и проверить класс, если установлено $ this-> person ["first_name"] и возвращает значение. Другим примером будет вызов $ this-> fetch_BookGenreTitle() и вернуть класс в значение $ this-> book ["genre"] ["title"]. Я знаю, что что-то вроде этого нужно было бы немного проверить, чтобы он автоматически определял это, например, с $ this-> book ["genre_title"] не существует, тогда он должен проверить на $ this-> book ["genre"] ["title"].Как я могу использовать __call для динамического возврата значений свойств

До сих пор я придумал код, который (по какой-то причине) работает для возврата значений массива (например, пример моего лица), но моя проблема быстро развивается, когда я пытаюсь вернуть значения многомерного массива (например, с моим примером выше). Говорю, я все еще пытаюсь придумать способ для метода __call проверить наличие одного, а если он не существует, то другой.

Пожалуйста, бросьте мне линию здесь. Я ударился головой о стену, пытаясь понять это, и это убивает меня.

<?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

не ленитесь. Добавьте Getters, который вам нужен, вместо того, чтобы нести штраф за производительность __call, не говоря уже о том, что это много работает. – Gordon

ответ

0

Учитывая "BookGenreTitle":

  1. Используйте какую-то регулярное выражение, чтобы отделить "Книга", "Жанр" и "Название"
  2. property_exists($this, "Book")
  3. array_key_exists("genre", $this->book)
  4. Если ключ существует, возврат $this->book["genre"]
  5. Если ключа не существует, array_key_exists("genre_title", $this->book)
  6. Если имеется ключ, возвращайтесь $this->book["genre_title"]
  7. Если ключ не существует, array_key_exists("genre", $this->book) && array_key_exists("title", $this->book["genre"])
  8. Keep собирается

Там, наверное, способ использовать цикл или какое-то рекурсия вместо жесткого кодирования максимальной глубины, но я не буду займитесь этим ...

О, и, как сказал другой плакат, вы хотите перегружать недвижимость (__get и __set).

+0

Я вижу, что вы имеете в виду в вашем примере. Таким образом, вместо запроса $ this-> fetch_BookGenreTitle() и метода __call, я бы запросил $ this-> fetch_BookGenreTitle в качестве свойства и использовал метод __get, верно? – waywardspooky

+0

@waywardspooky Да, точно. Не уверен, сколько разницы в производительности он сделал бы (это все волшебство в любом случае), но нет причин использовать методы, если вам не нужно передавать аргументы. О, и опустите префикс 'fetch_', это уродливо и не нужно. – kijin

0

Вы должны взглянуть на property overloading, не method overloading, как вы уже поняли, в названии Вопрос в себе.

+0

Спасибо. Я экспериментировал с __set и __get некоторое время назад, но по какой-то причине мне не приходило в голову идти этим путем. – waywardspooky

1

Еще раз спасибо.Я думаю, что у меня наконец есть мое решение, которое работает для многомерных массивов или любой глубины и учитывает, является ли это свойство, например $ this-> book ["genre_title"] или $ this-> book ["genre" ] [ «название»] :)

Я отправляю ниже код, как кто-то может случайно оказаться полезным в будущем

<?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; 
?> 

Там более чем вероятно, некоторые способы улучшения/рационализировать код , и в этом случае любой, кто хочет это сделать, более чем приветствуется, чтобы опубликовать улучшенную версию.

Смежные вопросы