Jak mogę natychmiast wykonać anonimową funkcję w PHP?

96

W JavaScript możesz zdefiniować anonimowe funkcje, które są wykonywane natychmiast:

(function () { /* do something */ })()

Czy możesz zrobić coś takiego w PHP?

Emanuil Rusev
źródło
2
Nie mam php 5.3 na rękach, aby wypróbować, ale jak to call_user_func(function(){/* stuff */})zrobić?
Jasper

Odpowiedzi:

121

W przypadku PHP7: zobacz odpowiedź Yasuo Ohgaki :(function() {echo 'Hi';})();

W przypadku poprzednich wersji: jedynym sposobem na ich natychmiastowe wykonanie jest

call_user_func(function() { echo 'executed'; });
Gordon
źródło
12
O ile nie zostanie wprowadzone (lub dopóki) nie zostanie wprowadzone łańcuchowanie wywołań funkcji , taka byłaby moja sugestia.
salathe
2
@Gordon: php 5.4 nadal nic?
dynamiczny
@ yes123 nope. nadal trzeba używaćcall_user_func
Gordon
2
@BennettMcElwee, powiedzmy to w ten sposób: nawet jeśli działa to nieco wolniej niż alternatywa zdefiniuj-przypisz-wywołanie, prawdopodobieństwo, że spowoduje to znaczące wąskie gardło w Twojej aplikacji jest bardzo niskie. w razie wątpliwości profiluj swoją aplikację w rzeczywistych warunkach.
Gordon,
Dzięki @Gordon, tak pomyślałem. Odniosłem wrażenie, że salathe i yes123 nie byli zadowoleni z tej metody i zastanawiałem się, dlaczego. Wydaje mi się to całkowicie w porządku.
Bennett McElwee
28

W PHP 7ma zrobić to samo w javascript

$gen = (function() {
    yield 1;
    yield 2;

    return 3;
})();

foreach ($gen as $val) {
    echo $val, PHP_EOL;
}

echo $gen->getReturn(), PHP_EOL;

Wynik to:

1
2
3
Wallace Maxters
źródło
15

Oczywiście możesz użyć call_user_func, ale jest jeszcze jedna całkiem prosta alternatywa:

<?php
// we simply need to write a simple function called run:
function run($f){
    $f();
}

// and then we can use it like this:
run(function(){
    echo "do something";
});

?>
Pacerier
źródło
1
Chcę funkcji wykonującej się natychmiast, ponieważ definiowana przeze mnie funkcja NIE POWINNA być wywoływana więcej niż raz podczas normalnego wykonywania. Problem ze zdefiniowaniem nazwanej funkcji run (), tak jak masz, polega na tym, że każdy, kto widzi kod, może pomyśleć, że może wywołać funkcję run () również w innej części kodu. Funkcja wykonująca się natychmiastowo wyjaśnia, że ​​ten kod nie powinien być uruchamiany dwukrotnie.
Daniel Howard
3
Nie mogą wywołać runtwojej funkcji w innej części kodu, ponieważ nie ma uchwytu do twojej funkcji istniejącego po linii, która natychmiast ją wykonuje.
Pacerier
3
@DanielHoward Celem run()jest natychmiastowe wykonanie przekazanej mu nienazwanej funkcji. To samo co call_user_func(), tylko żadne parametry nie są przekazywane.
Cypher,
1
@JordanLev, Ma prostszą implementację (tylko jeden wiersz:) $f();i może być szybszy, jeśli używany silnik nie optymalizuje się dla specjalnego przypadku, w którym call_user_funcma tylko jeden argument funkcji. Dzieje się tak, ponieważ call_user_funcobsługuje przekazywanie wielu parametrów, a jego pierwszy argument obsługuje ciąg jako argument lub funkcję. To powiedziawszy, jeśli call_user_funcjest dużo czytelny, nie użyłbym,run chyba że kod znajduje się gdzieś na dole piramidy .
Pacerier
1
@JordanLev, „prostsza implementacja” odnosi się do porównania między kodem wewnątrz funkcji runi call_user_func. call_user_funcma nieodłączną wadę w porównaniu z tym, runże runrobi tylko jedną rzecz, podczas gdy call_user_funcobsługuje dodatkowe funkcje oprócz robienia tego, co runrobi. Możesz wypróbować szybki test pętli ( np. ), Aby sprawdzić, który jest szybszy w Twoim silniku.
Pacerier,
11

To jest najprostsze dla PHP 7.0 lub nowszego.

php -r '(function() {echo 'Hi';})();'

Oznacza to utworzenie domknięcia, a następnie wywołanie go jako funkcji, podążając za „()”. Działa podobnie jak JS dzięki jednolitej kolejności oceny zmiennych.

https://3v4l.org/06EL3

Yasuo Ohgaki
źródło
2
Dobra odpowiedź, ale dlaczego formatujesz ją jako operację wiersza poleceń?
Kodos Johnson
6
(new ReflectionFunction(function() {
 // body function
}))->invoke();
innermond
źródło
6
czy możesz podać więcej szczegółów? może dodać wyjaśnienie?
MoralCode
2

Zauważ, że zaakceptowana odpowiedź jest w porządku, ale zajmuje 1,41 razy dłużej (41% wolniej) niż zadeklarowanie funkcji i wywołanie jej w dwóch wierszach.

[Wiem, że to naprawdę nie jest nowa odpowiedź, ale uznałem, że warto dodać ją gdzieś dla gości.]

Detale:

<?php
# Tags: benchmark, call_user_func, anonymous function 
require_once("Benchmark.php");
bench(array(
        'test1_anonfunc_call' => function(){
                $f = function(){
                        $x = 123;
                };
                $f();
        },
        'test2_anonfunc_call_user_func' => function(){
                call_user_func(
                        function(){
                                $x = 123;
                        }
                );
        }
), 10000);
?>

Wyniki:

$ php test8.php
test1_anonfunc_call took 0.0081379413604736s (1228812.0001172/s)
test2_anonfunc_call_user_func took 0.011472940444946s (871616.13432805/s)
Shovas
źródło
0

Wypróbowałem to w ten sposób, ale jest to bardziej szczegółowe niż najlepsza odpowiedź, używając dowolnego operatora (lub funkcji), który pozwala najpierw zdefiniować funkcję:

    $value = $hack == ($hack = function(){
            // just a hack way of executing an anonymous function
            return array(0, 1, 2, 3);                
    }) ? $hack() : $hack();
Paul Jerome Bordallo
źródło
2
Więc dlaczego nie po prostu $hack = function(){...}; $hack()?
0

To nie jest bezpośrednia odpowiedź, ale obejście. Korzystanie z PHP> = 7. Definiowanie anonimowej klasy za pomocą nazwanej metody i konstruowanie klasy oraz natychmiastowe wywołanie metody.

$var = (new class() { // Anonymous class
    function cool() { // Named method
        return 'neato';
    }
})->cool(); // Instantiate the anonymous class and call the named method
echo $var; // Echos neato to console.
thecoolestname36
źródło
-2

Nie wykonano natychmiast, ale blisko;)

<?php

$var = (function(){ echo 'do something'; });
$var();

?>
James
źródło