2010-10-28 29 views
0

我一直在想一種方法來動態地使用__call來返回一個類的屬性值,而不是創建一個函數,其唯一目的是返回這些值。我的想法是能夠請求(例如)$ this-> fetch_PersonFirstName(),並且如果設置了$ this-> person [「first_name」]並返回該值,那麼請檢查類。另一個例子是呼叫$ this-> fetch_BookGenreTitle()並且該類返回值$ this-> book [「genre」] [「title」]。我知道這樣的事情需要做一些檢查,以便它自動確定,例如,因爲$ this-> book [「genre_title」]不存在,那麼它應該檢查$ this-> book [「流派」] [「標題」]如何使用__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

不要懶惰。添加你需要的吸氣劑,而不是引發__呼吸的性能損失,更不用說做了這麼多工作的人。 – Gordon 2010-10-28 13:18:50

回答

0

鑑於 「BookGenreTitle」:

  1. 使用某種形式的正則表達式的分離 「尚書」, 「流派」 和 「標題」
  2. property_exists($this, "Book")
  3. ​​
  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. 繼續下去

有可能使用循環或某種遞歸的,而不是硬編碼的最大深度的方式,但我不會進入現在...

哦,和其他海報說,你想要的是財產超載(__get__set)。

+0

我在你的例子中看到你的意思。因此,我不會請求$ this-> fetch_BookGenreTitle()和__call方法,而是請求$ this-> fetch_BookGenreTitle作爲屬性並使用__get方法,對吧? – waywardspooky 2010-10-28 14:02:15

+0

@waywardspooky確實如此。不知道它會造成多大的性能差異(無論如何它都是魔術),但除非需要傳遞參數,否則沒有理由使用方法。哦,並刪除'fetch_'前綴,這是醜陋的和不必要的。 – kijin 2010-10-28 14:11:07

0

你需要看看property overloading,不method overloading因爲你已經在自己的問題的標題想通了。

+0

謝謝。前段時間,我嘗試過__set和__get,但由於某種原因,我沒有想到通過這種方式走這條路線。 – waywardspooky 2010-10-28 13:57:49

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

還有更可能一些方法來提高/精簡代碼有用在這種情況下,任何想要這樣做的人都歡迎發佈改進版本。