2013-07-25 5 views
15

Есть ли способ остановить array_walk внутри анонимной функции?Перерыв array_walk от анонимной функции

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

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

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

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

Использование break/continue не работает (ошибка: Fatal error: Cannot break/continue 1 level in ...).

Примечание: Я не хочу, чтобы переписать код, я просто хочу знать IF это возможно.

+3

Вы * можете * бросить, затем поймать, Исключение. Конечно, это неправильный подход, но это возможно. –

+0

Невозможно напрямую, но где именно вы рисуете линию для переписывания кода? (Решение «Исключение» похоже на работу, но я бы скорее использовал простой «foreach», чем это сделал. – Jon

+0

@Jon: Ну, мне было любопытно, можно ли выполнять такие функции. Я бы не хотел использовать 'for' /' foreach', вот и все (в основном теоретический вопрос :)). Энтони, вы должны опубликовать это как ответ. –

ответ

11

Как уже было сказано, теоретически это возможно, но я бы посоветовал это сделать. Вот как использовать Исключение для выхода из 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

Это может быть полезно, если это проверка ядра в вашем приложении, и вы все равно будете исключать исключение. Выполнение чего-то типа «throw new InvalidInputException;», а затем правильное обращение с ним. Но в большинстве случаев лучше не делать этого :) Спасибо за ответ! –

6

Вы можете поставить статический флаг внутри анонимной функции:

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

    // … your code 

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

Это на самом деле не остановить итерации, но все последующие циклы после того, как флаг просто ничего не делать. Не очень эффективный, но он может работать без какого-либо увеличения производительности, если массивы, обработанные повторно, не слишком велики.

В вашем случае код будет:

$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'; 

Но на самом деле это не будет большой разницы, если не было «перерыв» на всех. Для каждого недопустимого значения будет назначаться только «ложь», что не имеет значения, поскольку результат будет по-прежнему ложным. Возможно, было бы еще эффективнее, чем моя статическая переменная.

лично в вашем случае я хотел бы использовать вместо array_filter:

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

или просто

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

Если все значения в массиве $parent числовые, они будут все присутствующие после фильтрации. С другой стороны, любое нечисловое значение в массиве будет влиять на содержимое (уменьшение количества элементов) в фильтрованном массиве, и сравнение даст false.

Смежные вопросы