2010-10-28 41 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; 
?> 

还有更可能一些方法来提高/精简代码有用在这种情况下,任何想要这样做的人都欢迎发布改进版本。