2013-07-25 18 views
15

Czy istnieje sposób na zatrzymanie funkcji anonimowej array_walk?Przerwa array_walk z anonimowej funkcji

Oto kilka przykładowy kod (który działa), aby pokazać, co mam na myśli, że sprawdza, czy tablica ma tylko wartości numeryczne.

$valid = true; 
array_walk($parent, function ($value) use (&$valid) { 
    if (!is_numeric($value)) { 
     $valid = false; 
    } 
}); 

return $valid ? 'Valid' : 'Invalid'; 

Jeśli mam wystarczająco duży wachlarz, a pierwsza pozycja jest nieważne, reszta (redundantne) kontrole są jeszcze zrobione, więc chciałbym zatrzymać egzekucję.

Używanie break/continue nie działa (błąd: Fatal error: Cannot break/continue 1 level in ...).

Uwaga: Nie chcę przepisać kod, po prostu chcę wiedzieć IF jest to możliwe.

+3

Możesz * rzucić, a następnie złapać wyjątek. Oczywiście to niewłaściwe podejście, ale jest to możliwe. –

+0

Nie możliwe bezpośrednio, ale gdzie dokładnie narysujesz linię do przepisywania kodu? (Rozwiązanie 'Exception' brzmi, jakby zadziałało, ale wolałbym użyć prostego' foreach' niż tego). – Jon

+0

@Jon: Cóż, byłem ciekawy, czy było to możliwe dla takich funkcji. Nie chciałbym używać 'for' /' foreach', to tyle (głównie teoretyczne pytanie :)). Anthony, powinieneś to opublikować jako odpowiedź. –

Odpowiedz

11

Jak już wspomniano, teoretycznie jest to możliwe, ale odradzam. Oto jak użyć wyjątku, aby wyrwać się z array_walk.

<?php 
$isValid = false; 

$array = range(1, 5); 

try { 
    array_walk($array, function($value) { 
     $isAMagicNumber = 3 === $value; 
     if ($isAMagicNumber) { 
      throw new Exception; 
     } 
    }); 
}catch(Exception $exception) { 
    $isValid = true; 
} 

var_dump($isValid); 

/* 
    bool(true) 
*/ 
+0

Może to być przydatne, jeśli jest to podstawowe sprawdzenie w aplikacji, i mimo to i tak wyrzuciłbyś wyjątek. Robi coś w stylu 'throw new InvalidInputException;', a następnie poprawnie go obsługuje. Ale w większości przypadków lepiej tego nie robić :) Dzięki za odpowiedź! –

6

Można umieścić statyczny flagę wewnątrz funkcji anonimowy:

array_walk($ary, function($item) { 
    static $done = false; 
    if($done) { 
     return; 
    } 

    // … your code 

    if($myBreakCondition) { 
     $done = true; 
     return; 
    } 
}); 

nie faktycznie zatrzymać iteracji, ale wszystkie kolejne cykle po flaga jest ustawiona po prostu nic nie robić. Niezbyt wydajne, ale może działać bez większego wpływu na wydajność, jeśli tablice iterowane nie są zbyt duże.

w Twoim przypadku, kod byłoby:

$valid = true; 
array_walk($parent, function($value) use(&$valid) { 
    static $done = false; 
    if($done) { 
     return; 
    } 

    if(!is_numeric($value)) { 
     $valid = false; 
     $done = true; 
     return; 
    } 
}); 
return $valid ? 'Valid' : 'Invalid'; 

Ale w rzeczywistości to nie będzie dużej różnicy, jeśli nie było „break” w ogóle. Dla każdej nieprawidłowej wartości zostanie przypisana tylko wartość "false", co nie ma znaczenia, ponieważ wynik będzie nadal fałszywy. Być może byłoby jeszcze bardziej wydajne, że moja zmienna statyczna oszukuje.

Osobiście w przypadku użyłbym array_filter zamiast:

$valid = count(array_filter($parent, 'is_numeric')) == count($parent); 

czy tylko

$valid = array_filter($parent, 'is_numeric')) == $parent; 

Jeśli wszystkie wartości w tablicy $parent są numeryczne, byliby wszyscy obecni po filtrowaniu. Z drugiej strony, każda wartość nieliczbowa w tablicy wpłynie na zawartość (zmniejszenie liczby elementów) w przefiltrowanej tablicy, a porównanie da fałszywe.