PHP: пространство имен и инъекция зависимостей (slim framework) [дубликат]

Проблема была хорошо идентифицирована. Но есть решение; make doSomething generic:

<T extends Animal> void doSomething<List<T> animals) {
}

теперь вы можете вызвать doSomething с помощью List & lt; Dog> или List & lt; Cat> или List & lt; Animal>.

87
задан hakre 18 April 2013 в 16:25
поделиться

11 ответов

Начиная с PHP7 вы можете сделать

$obj = new StdClass;
$obj->fn = function($arg) { return "Hello $arg"; };
echo ($obj->fn)('World');

или использовать Closure :: call () , хотя это не работает на StdClass.


До PHP7 вам необходимо реализовать метод magic __call для перехвата вызова и вызвать обратный вызов (что невозможно для StdClass, конечно, потому что вы не можете добавить __call ])

class Foo
{
    public function __call($method, $args)
    {
        if(is_callable(array($this, $method))) {
            return call_user_func_array($this->$method, $args);
        }
        // else throw exception
    }
}

$foo = new Foo;
$foo->cb = function($who) { return "Hello $who"; };
echo $foo->cb('World');

Обратите внимание, что вы не можете делать

return call_user_func_array(array($this, $method), $args);

в теле __call, потому что это вызовет __call в бесконечном цикле.

72
ответ дан Gordon 25 August 2018 в 02:20
поделиться

Вы можете сделать это, вызвав __invoke при закрытии, так как это магический метод, который объекты используют для работы как функции:

$obj = new stdClass();
$obj->callback = function() {
    print "HelloWorld!";
};
$obj->callback->__invoke();

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

96
ответ дан Brilliand 25 August 2018 в 02:20
поделиться

Поскольку PHP 7 замыкание можно вызвать с помощью метода call() :

$obj->callback->call($obj);

Так как PHP 7 также можно выполнять операции над произвольными выражениями (...) (как объясняется Korikulum ):

($obj->callback)();

Другими распространенными подходами PHP 5 являются:

  • с использованием магического метода __invoke() (как объяснено Brilliand )
    $obj->callback->__invoke();
    
  • с использованием call_user_func()
    call_user_func($obj->callback);
    
  • с использованием промежуточной переменной в выражении
    ($_ = $obj->callback) && $_();
    

Каждый способ имеет свои собственные профи и минус, но наиболее радикальное и окончательное решение по-прежнему остается тем, что представлено Гордоном .

class stdKlass
{
    public function __call($method, $arguments)
    {
        // is_callable([$this, $method])
        //   returns always true when __call() is defined.

        // is_callable($this->$method)
        //   triggers a "PHP Notice: Undefined property" in case of missing property.

        if (isset($this->$method) && is_callable($this->$method)) {
            return call_user_func($this->$method, ...$arguments);
        }

        // throw exception
    }
}

$obj = new stdKlass();
$obj->callback = function() { print "HelloWorld!"; };
$obj->callback();
5
ответ дан Community 25 August 2018 в 02:20
поделиться

хорошо, следует подчеркнуть, что сохранение замыкания в переменной и вызов varible на самом деле (wierdly) быстрее, в зависимости от суммы вызова, становится довольно много, с xdebug (так очень точное измерение), мы говорят о 1,5 (фактор, используя переменную, вместо прямого вызова __invoke, поэтому вместо этого просто сохраните закрытие в varible и назовите его.

2
ответ дан Kmtdk 25 August 2018 в 02:20
поделиться

Начиная с PHP 7 вы можете сделать следующее:

($obj->callback)();
14
ответ дан Korikulum 25 August 2018 в 02:20
поделиться

Если вы используете PHP 5.4 или выше, вы можете привязать вызываемый к области вашего объекта вызов вызываемого пользовательского поведения. Так, например, если бы у вас была следующая настройка ..

function run_method($object, Closure $method)
{
    $prop = uniqid();
    $object->$prop = \Closure::bind($method, $object, $object);
    $object->$prop->__invoke();
    unset($object->$prop);
}

И вы работали в таком классе ..

class Foo
{
    private $value;
    public function getValue()
    {
        return $this->value;
    }
}

Вы можете запустить свой собственный логики, как если бы вы работали из области вашего объекта

$foo = new Foo();
run_method($foo, function(){
    $this->value = 'something else';
});

echo $foo->getValue(); // prints "something else"
0
ответ дан Lee Davis 25 August 2018 в 02:20
поделиться

Вот еще одна альтернатива, основанная на принятом ответе, но прямое расширение stdClass:

class stdClassExt extends stdClass {
    public function __call($method, $args)
    {
        if (isset($this->$method)) {
            $func = $this->$method;
            return call_user_func_array($func, $args);
        }
    }
}

Пример использования:

$foo = new stdClassExt;
$foo->blub = 42;
$foo->whooho = function () { return 1; };
echo $foo->whooho();

Вероятно, вам лучше использовать call_user_func или __invoke.

1
ответ дан Mahn 25 August 2018 в 02:20
поделиться

Ну, если вы действительно настаиваете. Другим обходным решением было бы следующее:

$obj = new ArrayObject(array(),2);

$obj->callback = function() {
    print "HelloWorld!";
};

$obj['callback']();

Но это не самый приятный синтаксис.

Однако парсер PHP всегда рассматривает T_OBJECT_OPERATOR, IDENTIFIER, ( как вызов метода , Кажется, нет обходного пути для создания -> обхода таблицы методов и доступа к атрибутам.

7
ответ дан mario 25 August 2018 в 02:20
поделиться

Вот еще один способ успешного вызова свойств объекта как закрытия. Если вы не хотите менять основной объект, используйте это:

$obj = new AnyObject(); // with or without __invoke() method
$obj->callback = function() {
     return function () {
          print "HelloWorld!";
     };
};
$obj->callback();  

UPDATE:

$obj = new AnyObject(); // with or without __invoke() method
$obj->callback = function() {
     print "HelloWorld!";
};
$callback = $obj->callback;  
$callback();
3
ответ дан Mohamad Rostami 25 August 2018 в 02:20
поделиться

Кажется, возможно использование call_user_func().

call_user_func($obj->callback);

не изящно, хотя .... То, что @Gordon говорит, вероятно, единственный способ пойти.

7
ответ дан Pekka 웃 25 August 2018 в 02:20
поделиться

Я знаю, что это старо, но я думаю, что черты прекрасно справляются с этой проблемой, если вы используете PHP 5.4 +

. Сначала создайте черту, которая делает свойства вызываемыми:

trait CallableProperty {
    public function __call($method, $args) {
        if (property_exists($this, $method) && is_callable($this->$method)) {
            return call_user_func_array($this->$method, $args);
        }
    }
}

Затем вы можете использовать эту черту в своих классах:

class CallableStdClass extends stdClass {
    use CallableProperty;
}

Теперь вы можете определить свойства через анонимные функции и вызвать их напрямую:

$foo = new CallableStdClass();
$foo->add = function ($a, $b) { return $a + $b; };
$foo->add(2, 2); // 4
5
ответ дан SteveK 25 August 2018 в 02:20
поделиться
Другие вопросы по тегам:

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