2013-07-25 16 views
15

C'è un modo per arrestare uno array_walk dall'interno della funzione anonima?Interrompe array_walk dalla funzione anonima

Ecco un esempio di codice (che funziona) per mostrare cosa intendo, che controlla se un array ha solo valori numerici.

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

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

Se ho una grande gamma abbastanza, e la prima voce è valida, il resto dei controlli (ridondante) sono ancora fatto, quindi vorrei fermare l'esecuzione.

L'utilizzo di break/continue non funziona (errore: Fatal error: Cannot break/continue 1 level in ...).

Nota: Non voglio riscrivere il codice, voglio solo sapere SE questo è possibile.

+3

Si * potrebbe * lanciare, quindi prendere, un'eccezione. Certo, è l'approccio sbagliato, ma è possibile. –

+0

Non possibile direttamente, ma dove esattamente si disegna la linea per riscrivere il codice? (La soluzione 'Exception' sembra funzionare, ma prima userei un semplice' foreach' piuttosto che farlo). – Jon

+0

@Jon: Beh, ero curioso di sapere se fosse possibile per funzioni come questa. Non mi piacerebbe usare 'for' /' foreach', questo è tutto (principalmente una domanda teorica :)). Anthony, dovresti postarlo come risposta. –

risposta

11

Come detto, teoricamente è possibile ma sconsiglio di farlo. Ecco come utilizzare un'eccezione per uscire da 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

Questo può essere utile se si tratta di un controllo di base nell'applicazione, e comunque si genererebbe un'eccezione. Fare qualcosa come "lanciare InvalidInputException;", quindi gestirlo correttamente. Ma nella maggior parte dei casi, è meglio non farlo :) Grazie per la risposta! –

6

Si può mettere una bandiera statica all'interno della funzione anonima:

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

    // … your code 

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

Questo in realtà non fermare l'iterazione, ma tutti gli ulteriori cicli dopo il flag è impostato semplicemente non fare nulla. Non molto efficiente, ma potrebbe funzionare senza un maggiore impatto sulle prestazioni se gli array ripetuti non sono troppo grandi.

Nel tuo caso, il codice sarebbe:

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

Ma in realtà non sarà molta differenza se non ci fosse “pausa” a tutti. Solo il "falso" verrebbe assegnato per ogni valore non valido, il che non importa in quanto il risultato sarebbe ancora falso. Forse sarebbe ancora più efficiente che la mia variabile statica tradisca.

personalmente nel caso Userei array_filter invece:

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

o semplicemente

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

Se tutti i valori nella matrice $parent sono numerici, sarebbero tutti presenti dopo il filtraggio. D'altra parte, qualsiasi valore non numerico nella matrice influirebbe sul contenuto (diminuendo il numero di elementi) nell'array filtrato e il confronto produrrebbe false.