2012-08-09 16 views
60

Non sono sicuro se la maschera di bit sia il termine corretto. Mi spiego:Come implementare una maschera di bit in PHP?

in php, la funzione error_reporting può essere chiamato più modi:

// Report simple running errors 
error_reporting(E_ERROR | E_WARNING | E_PARSE); 

// Reporting E_NOTICE can be good too (to report uninitialized 
// variables or catch variable name misspellings ...) 
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); 

// Report all errors except E_NOTICE 
// This is the default value set in php.ini 
error_reporting(E_ALL^E_NOTICE); 

ho ricevuto la maschera di bit termine dalla pagina php.net here

In ogni caso il punto di questo è, Ho implementato un metodo SEMPLICE chiamato ls che restituisce il contenuto di una directory.

Questa funzione prende 3 args ... ($ include_hidden = false, $ return_absolute = false, $ ext = false)

Così, quando chiamo la funzione, ho impostato come voglio i risultati. Se voglio i risultati da restituire le directory nascoste, se voglio BaseNames solo ecc

in modo che quando chiamo la funzione sto scrivendo

ls(true, false, true) 
ls(false, false, true) 
ls(true, true, true) 
etc... 

ho pensato che sarebbe stato molto più leggibile se solo potessi Segnala come voglio che i dati vengano restituiti?

così qualcosa di simile:

ls(INCLUDE_HIDDEN | HIDE_EXTS); 
ls(SHOW_ABSOLUTE_PATHS | HIDE_EXTS); 

ecc ...

Come potrei implementare questo in termini di sperimentazione, che le bandiere sono stati chiamati?

+1

bene chiesto. KISS – Nico

risposta

121

E 'abbastanza semplice in realtà. Prima un po 'di codice per dimostrare come può essere implementato. Se non si capisce nulla di ciò che questo codice sta facendo o come funziona, non esitate a chiedere ulteriori domande nei commenti:

const FLAG_1 = 0b0001; // 1 
const FLAG_2 = 0b0010; // 2 
const FLAG_3 = 0b0100; // 4 
const FLAG_4 = 0b1000; // 8 
// Can you see the pattern? ;-) 

function show_flags ($flags) { 
    if ($flags & FLAG_1) { 
    echo "You passed flag 1!<br>\n"; 
    } 
    if ($flags & FLAG_2) { 
    echo "You passed flag 2!<br>\n"; 
    } 
    if ($flags & FLAG_3) { 
    echo "You passed flag 3!<br>\n"; 
    } 
    if ($flags & FLAG_4) { 
    echo "You passed flag 4!<br>\n"; 
    } 
} 

show_flags(FLAG_1 | FLAG_3); 

Demo


Perché le bandiere sono interi, su una piattaforma a 32 bit si definiscono fino a 32 flag. Su una piattaforma a 64 bit, è 64. È anche possibile definire i flag come stringhe, nel qual caso il numero di flag disponibili è più o meno infinito (entro i limiti delle risorse di sistema, ovviamente). Ecco come funziona in binario (ridotto per interi a 8 bit per semplicità).

FLAG_1 
Dec: 1 
Binary: 00000001 

FLAG_2 
Dec: 2 
Binary: 00000010 

FLAG_3 
Dec: 4 
Binary: 00000100 

// And so on... 

Quando si combinano i flag per passarli alla funzione, li si OPPURE insieme. Diamo uno sguardo a ciò che accade quando si passa FLAG_1 | FLAG_3

00000001 
| 00000100 
= 00000101 

e quando si vuole vedere che le bandiere sono stati fissati, tu e la maschera di bit con la bandiera. Quindi, consente di dare il risultato di cui sopra e vedere se FLAG_3 è stato fissato:

00000101 
& 00000100 
= 00000100 

...otteniamo il valore della bandiera di nuovo, un intero diverso da zero - ma se vediamo se è stato fissato:

00000101 
& 00000010 
= 00000000 

... otteniamo zero. Ciò significa che puoi semplicemente valutare il risultato dell'operazione AND come booleano quando verifichi se il valore è stato passato.

+5

Quindi le operazioni bitwise di base sono: '$ flags & FLAG_1' - controlla se FLAG_1 è impostato , '$ flags | FLAG_1' - imposta FLAG_1, '$ flags & ~ FLAG_1' - disattiva FLAG_1,' ~ $ flags' - inverti flags –

+5

Non conosco PHP e probabilmente non lo imparerò mai, ma sono felice di essermi imbattuto in questa domanda - la tua spiegazione può aiutare chiunque a implementare la mappatura dei bit in qualsiasi lingua :) –

+3

Vorrei raccomandare di definire i decimali di potenza 2 come operazione di shift bit-saggio di 1. 'define ('FLAG_1', 1 << 0); define ('FLAG_2', 1 << 2); define ('FLAG_3', 1 << 3); define ('FLAG_4', 1 << 4); 'Questo è come solitamente si fa in C – AmitP

14
define("INCLUDE_HIDDEN", 0x1); 
define("HIDE_EXTS", 0x2); 
define("SHOW_ABSOLUTE_PATHS", 0x4); 
//And so on, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800 etc.. 

È quindi possibile verificare la presenza di singole bandiere nella funzione ls:

if($flags & INCLUDE_HIDDEN) { //<-- note just a single &, bitwise and 
    //$flags have INCLUDE_HIDDEN 
} 
+7

Sapete di un vantaggio nell'usare numeri esadecimali invece di numeri interi? Semplicemente curioso :) –

+0

@ AlexMorley-Finch sembra che sia puramente preferenziale, usando decimali o hex non sembra cambiare il tempo di esecuzione, o –

3

Gli altri hanno offerto buoni suggerimenti, ma in questi giorni è molto più comune passare in array associativi invece di maschere di bit. È molto più leggibile e consente di passare altre variabili oltre ai valori vero/falso. Qualcosa del genere:

myFunction(['includeHidden' => true, 'fileExts' => false, 'string' => 'Xyz']); 

function myFunction($options) { 
    // Set the default options 
    $options += [ 
     'includeHidden' => false, 
     'fileExts' => true, 
     'string' => 'Abc', 
    ]; 

    if ($options['includeHidden']) { 
     ... 
    } 
    ... 
} 
+0

Anch'io lo facevo in questo modo, ma i compagni di compagni si lamentano del fatto che non ci sia "suggerimento tipo" nei loro IDE, nessun commento [doc] (https://en.wikipedia.org/wiki/PHPDoc) e la funzione non [lancia errori quando i parametri richiesti non vengono passati] (http://symfony.com/doc/current/components/options_resolver.html). Idealmente "params nominati" risolverebbe tutti questi problemi se esistessero in php –

+0

Ciao @TimoHuovinen - grazie per il commento. È facile aggiungere commenti al doc che descrivono le opzioni e i valori predefiniti, generano un'eccezione se necessario e impostano il parametro su un array che consente di suggerire il tipo. Funzionerà per te? –

+0

Oh capisco. La classe Symfony OptionsResolver fa un passo avanti per offrire ancora più funzionalità. Freddo. –

Problemi correlati