2014-09-02 3 views
2

Я использую API, который возвращает разные значения, и я хочу динамически сказать моему классу, чтобы он запускал функцию с тем же именем (так что мне не понадобится огромный switch или if/else беспорядок).Объявление и вызов функций объекта PHP с периодом по имени

  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] *.

Это также относится к методам класса.

Как Walkaround, вы можете следовать по пути, который вы предложили себя:

$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

Хорошо, понял, как много. Благодаря!Похоже, мне нужно будет проявить творческий подход. –

+0

@ d -_- b см. Проходы. Я скоро буду обновляться. – BlitZ

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 - Спасибо, это похоже на то, что я * должен делать! –

+0

+1, но в чем смысл хранить копию объекта внутри '$ this-> classes' (тем более, что он перезаписывается)? – FuzzyTree

+0

Чисто не нужно определять свойство для каждого имени дочернего класса - вместо этого сохраните их в массиве. Нет разницы между этим и '$ this -> {$ class}', если вы хотите определить его для каждого возможного ребенка. –

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