bene o nel male, loose-digitazione è "The Way PHP". Molti dei built-in, e la maggior parte dei costrutti linguistici, funzioneranno su qualunque tipo li forniate - silenziosamente (e spesso pericolosamente) proiettandoli dietro le quinte per far combaciare le cose (un po ').
Venendo da una Java/C/C++ fondo me stesso, il modello loose-tipizzazione di PHP è sempre stata una fonte di frustrazione per me. Ma nel corso degli anni ho scoperto che, se devo scrivere PHP, posso fare un lavoro migliore (codice più pulito, più sicuro, più testabile) abbracciando la "scioltezza" di PHP, piuttosto che combatterlo; e io finisco per essere una scimmia più felice per questo.
Il casting è fondamentale per la mia tecnica e (IMHO) è l'unico modo per creare in modo coerente codice PHP pulito e leggibile che gestisca argomenti di tipo misto in un modo comprensibile, testabile e deterministico.
Il punto principale (che si capisce chiaramente) è che, in PHP, non si può semplicemente presumere che un argomento sia il tipo che ci si aspetta che sia. In questo modo, potresti avere gravi conseguenze che probabilmente non riuscirai a rilevare fino a quando la tua app non sarà in produzione.
Per illustrare questo punto:
<?php
function displayRoomCount($numBoys, $numGirls) {
// we'll assume both args are int
// check boundary conditions
if(($numBoys < 0) || ($numGirls < 0)) throw new Exception('argument out of range');
// perform the specified logic
$total = $numBoys + $numGirls;
print("{$total} people: {$numBoys} boys, and {$numGirls} girls \n");
}
displayRoomCount(0, 0); // (ok) prints: "0 people: 0 boys, and 0 girls"
displayRoomCount(-10, 20); // (ok) throws an exception
displayRoomCount("asdf", 10); // (wrong!) prints: "10 people: asdf boys, and 10 girls"
Un approccio per risolvere questo è quello di limitare i tipi che la funzione può accettare, un'eccezione quando viene rilevato un tipo non valido. Altri hanno già menzionato questo approccio. Appare bene alla mia estetica Java/C/C++, e ho seguito questo approccio in PHP per anni e anni. In breve, non c'è niente di sbagliato in questo, ma va contro "The PHP Way", e dopo un po 'di tempo inizia a sentirmi come un tuffo.
In alternativa, il casting fornisce un modo semplice e pulito per garantire che la funzione si comporti in modo deterministico per tutti i possibili input, senza dover scrivere una logica specifica per gestire ogni tipo diverso.
Utilizzando fusione, il nostro esempio diventa ora:
<?php
function displayRoomCount($numBoys, $numGirls) {
// we cast to ensure that we have the types we expect
$numBoys = (int)$numBoys;
$numGirls = (int)$numGirls;
// check boundary conditions
if(($numBoys < 0) || ($numGirls < 0)) throw new Exception('argument out of range');
// perform the specified logic
$total = $numBoys + $numGirls;
print("{$total} people: {$numBoys} boys, and {$numGirls} girls \n");
}
displayRoomCount("asdf", 10); // (ok now!) prints: "10 people: 0 boys, and 10 girls"
La funzione ora si comporta come previsto. In effetti, è facile dimostrare che il comportamento della funzione è ora ben definito per tutti gli ingressi possibili. Questo perché l'operazione di cast è ben definita per tutti i possibili input; i cast assicurano che lavoriamo sempre con i numeri interi; e il resto della funzione è scritto in modo da essere ben definito per tutti i possibili numeri interi.
Rules for type-casting in PHP are documented here, (vedere i collegamenti specifici del tipo a metà della pagina, ad esempio: "Conversione in intero").
Questo approccio ha il vantaggio aggiunto che la funzione si comporterà ora in modo coerente con altri built-in PHP e costrutti del linguaggio. Per esempio:
// assume $db_row read from a database of some sort
displayRoomCount($db_row['boys'], $db_row['girls']);
funzionano bene, nonostante il fatto che $db_row['boys']
e $db_row['girls']
sono in realtà le stringhe che contengono valori numerici. Ciò è coerente con il modo in cui lo sviluppatore PHP medio (che non conosce C, C++ o Java) si aspetta che funzioni.
Per quanto riguarda la fusione valori di ritorno: c'è ben poco senso farlo, a meno che non si sa di avere una variabile potenzialmente di tipo misto, e si desidera assicurarsi sempre che il valore di ritorno è un tipo specifico. Questo è più spesso il caso nei punti intermedi del codice, piuttosto che nel punto in cui si sta tornando da una funzione.
Un esempio pratico:
<?php
function getParam($name, $idx=0) {
$name = (string)$name;
$idx = (int)$idx;
if($name==='') return null;
if($idx<0) $idx=0;
// $_REQUEST[$name] could be null, or string, or array
// this depends on the web request that came in. Our use of
// the array cast here, lets us write generic logic to deal with them all
//
$param = (array)$_REQUEST[$name];
if(count($param) <= $idx) return null;
return $param[$idx];
}
// here, the cast is used to ensure that we always get a string
// even if "fullName" was missing from the request, the cast will convert
// the returned NULL value into an empty string.
$full_name = (string)getParam("fullName");
si ottiene l'idea.
ci sono un paio di gotcha di essere a conoscenza del meccanismo di fusione
di PHP non è abbastanza intelligente per ottimizzare la "no-op" cast. Pertanto, la trasmissione sempre causa la creazione di una copia della variabile. Nella maggior parte dei casi, questo non è un problema, ma se usi regolarmente questo approccio, dovresti tenerlo nella parte posteriore della tua mente. Per questo motivo, la trasmissione può causare problemi imprevisti con riferimenti e array di grandi dimensioni. Vedi PHP Bug Report #50894 per maggiori dettagli.
In PHP, un numero intero che è troppo grande (o troppo piccolo) per rappresentare come un tipo intero, verrà automaticamente rappresentato come un float (o un double, se necessario). Ciò significa che il risultato di ($big_int + $big_int)
può essere effettivamente un float e, se lo si trasmette a un int, il numero risultante sarà privo di significato. Quindi, se stai costruendo funzioni che devono operare su grandi numeri interi, dovresti tenerlo a mente e probabilmente prendere in considerazione un altro approccio.
Ci scusiamo per il lungo post, ma è un argomento che ho considerato in profondità, e nel corso degli anni, ho accumulato un po 'di conoscenza (e di opinione) su di esso. Esponendolo qui, spero che qualcuno lo troverà utile.
Si potrebbe pensare che la digitazione debole (come in PHP, javascript, Smalltalk, c, C++, ecc.) Sia un difetto, ma è parte del design di PHP, e quindi improbabile che cambi. È anche una delle caratteristiche che rendono PHP un linguaggio di tipo c. – GZipp
@GZopp: C e C++ non sono linguaggi tipizzati debolmente. –
In realtà si può richiedere che gli argomenti siano di un certo tipo, ma funziona solo con classi e matrici, non con altri tipi built-in. http://www.php.net/manual/en/functions.arguments.php#98425 – mwhite