Функции лямбды в PHP не Логичны

Примечание: Я уплотнил эту статью в свою личность Wiki: http://wiki.chacha102.com/Lambda - Обладает

Я испытываю некоторые затруднения из-за функций стиля Лямбды в PHP.

Во-первых, это работает:

$foo = function(){ echo "bar"; };
$foo();

Во-вторых, это работает:

class Bar{
    public function foo(){
       echo "Bar";
    }

В-третьих, Это работает:

$foo = new stdClass;
$foo->bar = function(){ echo "bar"; };
$test = $foo->bar;
$test();

Но, это не работает:

$foo = new stdClass;
$foo->bar = function(){ echo "bar"; };
$foo->bar();

И, это не работает

class Bar{
    public function foo(){
       echo "Bar";
    }
$foo = new Bar;
$foo->foo = function(){ echo "foo"; };
$foo->foo(); // echo's bar instead of Foo.

Мой Вопрос состоит в том Почему?, и как может я гарантировать что оба это:

$foo->bar = function(){ echo "test"; };
$foo->bar();

и это

$foo = new Bar;
$foo->bar();

названы правильно? Дополнительные очки, если Вы можете указать на документацию, указывающую, почему эта проблема происходит.

13
задан Tyler Carter 17 January 2010 в 22:33
поделиться

6 ответов

Это интересный вопрос. Это работает:

$a = new stdClass;
$a->foo = function() { echo "bar"; };
$b = $a->foo;
$b(); // echos bars

но, как вы говорите, это не так:

$a = new stdClass;
$a->foo = function() { echo "bar"; };
$a->foo();

Если вы хотите получить объект, к которому можно динамически вызывать членов, попробуйте:

class A {
  public function __call($func, $args) {
    $f = $this->$func;
    if (is_callable($f)) {
      return call_user_func_array($f, $args);
    }
  }
}

$a = new A;
$a->foo = function() { echo "bar\n"; };
$a->foo2 = function($args) { print_r($args); };
$a->foo();
$a->foo2(array(1 => 2, 3 => 4));

но вы не можете заменить вызываемые методы таким образом, потому что __call() вызываются только для методов, которые либо не существуют, либо недоступны (например, они приватны).

9
ответ дан 2 December 2019 в 00:17
поделиться

Вы не получите никакого повышения производительности ни для одного из них. Реальный вопрос в том, какой из них более полезен.

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

Если имеется какая-то сложная вложенная конфигурация, например:

$config->facebook->apikey = 'secret_key';
$config->facebook->url = 'http://www.facebook.com';

Можно использовать массив или API конфигурации, предоставленный одним из множества рамок ( Zend _ Config не является плохим)

-121--4631870-

По существу, статические методы позволяют писать процедурный код на объектно-ориентированном языке. Она позволяет вызывать методы без необходимости создания объекта в первую очередь.

-121--936361-

Функции и методы в PHP обрабатываются по-разному. Для добавления метода в класс можно использовать runkit _ method _ add () , но я не знаю способа добавления метода в экземпляр.

3
ответ дан 2 December 2019 в 00:17
поделиться

Интересный вопрос, хотя я не вижу причин, почему это должно работать:

class Bar{
    public function foo(){
       echo "Bar";
    }
$foo = new Bar;
$foo->foo = function(){ echo "foo"; };
$foo->foo(); // echo's bar instead of Foo.

У меня была аналогичная проблема с __ invoke () , и я также не смог решить ее:

class base {
    function __construct() {
        $this->sub = new sub();
    }

    function __call($m, $a) {
    }
}

class sub {
    function __invoke($a) {
    }
}

$b = new base();
$b->sub('test'); // should trigger base::__call('sub', 'test') or sub::__invoke('test')?

Решение? Никогда не используйте __, призывают () !: P

1
ответ дан 2 December 2019 в 00:17
поделиться

Ближе всего к этому можно было бы подойти, используя перегрузку __call, чтобы проверить, содержит ли свойство закрытие:

class what {
  function __call($name, $args) {
    $f= $this->$name;
    if ($f instanceof Closure) {
      $f();
    }
  }
}

$foo = new what();
$foo->bar = function(){ echo "bar"; };
$foo->bar();

Хотя учтите следующее примечание из документов:

Анонимные функции в настоящее время реализованный с использованием класса Closure. Это деталь реализации и не стоит полагаться.

Reference: Anonymous functions

1
ответ дан 2 December 2019 в 00:17
поделиться

Мне это кажется ошибкой, а не «причудой»:

<?php
$t = new stdClass;
$t->a = function() { echo "123"; };
var_dump($t);
echo "<br><br>";
$x = (array)$t;
var_dump($x);
echo "<br><br>";
$x["a"]();
echo "<br><br>";
?>

object(stdClass)#1 (1) { ["a"]=> object(Closure)#2 (0) { } } 

array(1) { ["a"]=> object(Closure)#2 (0) { } } 

123

Он есть, я просто не думаю, что PHP умеет его запускать.

0
ответ дан 2 December 2019 в 00:17
поделиться

Подумайте вот о чем:

<?php

class A {

    public $foo

    public function foo() {
        return 'The method foo';
    }

}

$obj = new A;
$obj->foo = function() { return 'The closure foo'; };

var_dump($obj->foo());

Вы имеете в виду $obj->foo() закрытие или $obj->foo() метод? Это двусмысленно, и PHP принимает решение, что вы имеете в виду метод. Чтобы использовать закрытие, вы должны определить, что вы имеете в виду. Один из способов сделать это - использовать временную переменную, как это сделали вы. Другой способ - использовать call_user_func($obj->foo).

Я не знаю другого простого способа.

0
ответ дан 2 December 2019 в 00:17
поделиться
Другие вопросы по тегам:

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