Создание динамических функций в классе с PHP [duplicate]

Одно правило большого пальца: спросите себя: «Имеет ли смысл называть этот метод, даже если объект Obj еще не создан?» Если это так, это определенно будет статичным.

Итак, в классе Car у вас может быть метод double convertMpgToKpl(double mpg), который будет статичным, потому что можно было бы знать, к чему преобразуется 35mpg, даже если никто когда-либо строил Автомобиль. Но void setMileage(double mpg) (который устанавливает эффективность одного конкретного автомобиля) не может быть статичным, так как немыслимо вызвать метод до того, как какой-либо автомобиль был сконструирован.

(Btw, обратное не всегда верно : иногда вы можете иметь метод, который включает в себя два объекта Car и все еще хочет, чтобы он был статичным. Например Car theMoreEfficientOf( Car c1, Car c2 ). Хотя это можно было бы преобразовать в нестатистическую версию, некоторые утверждают, что, поскольку нет «привилегированный» выбор того, какой автомобиль более важен, вы не должны заставлять вызывающего абонента выбирать один автомобиль как объект, на который вы будете ссылаться на этот метод. Однако эта ситуация составляет довольно небольшую часть всех статических методов.)

68
задан hakre 18 April 2013 в 18:11
поделиться

2 ответа

В PHP методы и свойства находятся в отдельном пространстве имен (у вас может быть метод и свойство с тем же именем), и независимо от того, используете ли вы свойство или метод, зависит от синтаксиса, который вы используете для этого.

$expr->something() - вызов метода, поэтому PHP будет искать something в списке методов класса.

$expr->something - это выборка свойств, поэтому PHP будет искать something в списке свойств класса.

$myInstance->lambda(); анализируется как вызов метода, поэтому PHP ищет метод с именем lambda в вашем классе, но такого метода нет (следовательно, Ошибка при вызове undefined method ).

Итак, вы должны использовать синтаксис fetch property для извлечения лямбда, а затем вызвать его.

]
  • Начиная с PHP 7.0, вы можете сделать это с помощью ($obj->lambda)():
    ($obj->lambda)();
    
    В скобках убедитесь, что PHP анализирует ($obj->lambda) как для получения свойства с именем lambda . Затем () вызывает результат извлечения свойства.
  • или вы можете сделать это с помощью ->lambda->__invoke():
    $myInstance = new MyClass();
    $myInstance->lambda->__invoke();
    
    __invoke является одним из PHP магические методы . Когда объект реализует этот метод, он становится invokable: его можно вызвать с помощью синтаксиса $var(). Анонимные функции - это экземпляры Closure , которые реализуют __invoke.
  • Или назначить его локальной переменной:
    $lambda = $myInstance->lambda;
    $lambda();
    
  • Или позвонить с помощью call_user_func:
    call_user_func($myInstance->lambda);
    
    call_user_func может вызывать любые callable , включая анонимные функции.
  • В качестве альтернативы, если это общий шаблон в ваш код, вы можете настроить метод __call для переадресации вызовов на ваш лямбда:
    class MyClass
    {
        private $lambda;
    
        public function __construct()
        {
            $this->lambda = function() {
                echo "Hello world!\n";
            };
        }
    
        public function __call($name, $args)
        {
            return call_user_func_array($this->$name, $args);
        }
    }
    
    Теперь это работает:
    $myInstance = new MyClass();
    $myInstance->lambda();
    
    С PHP 5.4 вы можете даже сделать это по признаку:
    trait LambdasAsMethods
    {
        public function __call($name, $args)
        {
            return call_user_func_array($this->$name, $args);
        }
    }
    
    class MyClass
    {
        use LambdasAsMethods;
    
        private $lambda;
    
        public function __construct()
        {
            $this->lambda = function() {
                echo "Hello World!\n";
            };
        }
    }
    
    $myInstance = new MyClass();
    $myInstance->lambda();
    
173
ответ дан arnaud576875 17 August 2018 в 13:59
поделиться
  • 1
    Приятно, хотя было бы неплохо увидеть записи __invoke/() vs. call_user_func. – user 16 January 2012 в 00:37
  • 2
    Так вот в чем черта может быть использована ... Я подумал ... – rodrigo-silveira 1 December 2012 в 09:54
  • 3
    вы можете использовать черты почти для всех, это не класс, а просто набор методов и реквизитов – Thielicious 17 September 2016 в 17:36

Вы также можете вызвать свою лямбда-функцию без каких-либо изменений в своем классе, используя ReflectionFunction.

$myInstance = new MyClass();
$lambda = new ReflectionFunction($myInstance->lambda);
$lambda->invoke();

или если вам нужно передать аргументы, то

$args = array('arg'=>'value');
$lambda->invokeArgs($args);
2
ответ дан akDeveloper 17 August 2018 в 13:59
поделиться
  • 1
    Это не самый короткий и самый эффективный способ обойти это. – amphetamachine 9 June 2017 в 21:17
Другие вопросы по тегам:

Похожие вопросы: