2014-09-02 64 views
2

的PHP對象函數我正在使用一個API返回不同的值,我想動態地告訴我的類運行一個具有相同名稱的函數(所以我不需要一個巨大的switch或者if/else亂七八糟)。聲明並調用名爲

  1. 如何聲明對象方法song.pause
  2. 如何使用對象方法song.pause
  3. 這可能是XY Problem,那麼有沒有更好的方法來做到這一點?我想到的一種選擇是始終呼叫str_replace('.','_',$type)並設置沒有句點的功能。思考?

例子:

<?php 
class MyClass { 
    ... 
    ... 
    $type = "song.pause"; // This value is returned from another API I can't control 

    if (property_exists('MyClass', $type)) { 
     $success = $this->{$type}(); // ??? 
    } else { 
     header("HTTP/1.1 400 Invalid type: $type); 
     exit; 
    } 


    public function 'song.pause'() { // obviously incorrect :) 
      ??? 
    } 

回答

2

不幸的是,你通常問的是不支持。來自manual

函數名稱遵循與PHP中其他標籤相同的規則。一個有效的 函數名稱以字母或下劃線開頭,後面跟着任意數字的字母,數字或下劃線。作爲一個正則表達式,它將如下表示:[a-zA-Z_ \ x7f- \ xff] [a-zA-Z0-9_ \ x7f- \ xff] *。

這也適用於類方法。

由於外觀圖釋,您可以按照您提出自己的方式:

$type = 'song.pause'; 
$type = str_replace('.', '_', $type); 
$this->{$type}(); // will call song_pause() 

或使用"dark" magic

<?php 
// header('Content-Type: text/plain; charset=utf-8'); 

class Test { 
    function __call($method, $args){ 
     // do redirect to proper processing method here 
     print_r($method); 
     echo PHP_EOL; 
     print_r($args); 
    } 
} 

$x = new Test(); 
$x->{'song.pause'}(1,2,3); 
?> 

表演:

song.pause   // < the method 
Array    // < arguments 
(
    [0] => 1 
    [1] => 2 
    [2] => 3 
) 

然而,「長「和真正透明的方式,我完全同意,is suggested by @scrowler

+0

好了,想通之多。謝謝!看起來我必須要有創意。 – 2014-09-02 03:07:53

+0

@d -_- b看看周遊。我會很快更新。 – BlitZ 2014-09-02 03:10:00

2

@ HAL9000是正確的:你想要什麼不被支持。一個潛在的解決方法是:

定義處理程序:

$typeHandlers = array(); 
$typeHandlers['song.pause'] = function() { 
    echo 'Pause!'; // or whatever... 
}; 

調用相應的處理程序:

$typeHandlers[$type](); 
3

鑑於song.pause回報,概念song應該是類名和pause應該是方法,考慮這種可能性:

class MyClass { 
    protected $classes = array(); 

    function processResponse($response) { 
     // $response example is "song.pause" 
     list($class, $method) = explode('.', $response); 
     if(!class_exists($class)) { 
      // Class doesn't exist 
      die("Class name {$class} doesn't exist! Exiting..."); 
     } 

     // Instantiate class 
     $this->classes[$class] = new $class(); 

     if(!method_exists($this->classes[$class], $method)) { 
      // Method doesn't exist within specified class 
      die("Method name {$method} doesn't exist within {$class}. Exiting..."); 
     } 

     // Call method 
     $result = $this->classes[$class]->{$method}(); 

     return $result; 
    } 
} 

你的邏輯的實現將是這樣的:

class song { 
    public function pause() { 
     return 'foobar'; 
    } 
} 

Here's an example.

+0

+1 - 謝謝,這看起來像我*應該*做的! – 2014-09-02 03:12:52

+0

+1但是在$ this-> classes裏面保留對象的拷貝是什麼意思(特別是在被覆蓋的時候)? – FuzzyTree 2014-09-02 03:16:36

+0

純粹是因爲不需要爲每個子類名稱定義屬性 - 而是將它們保留在數組中。如果你想爲每個可能的孩子定義它,那麼和$'this - > {$ class}'沒有區別。 – 2014-09-02 03:18:58