Test su interi e loro comportamento

Jonathan Stoppani (st.jonathan@gmail.com), 12/08/2006

Si vuole creare un test per eseguire un controllo dell'input di un utente. La variabile in entrata costituisce un ID ed è quindi (nel nostro caso) un intero positivo rappresentato con un tipo stringa. Vedremo ora quale combinazione di test risulti la soluzione migliore per eseguire il compito.

Valori usati per il test

Il terzo valore (int(170)) viene automaticamente convertito ad intero da php, da notare nel codice l'assegnamento con 0xAA.

[0] => string(2) "AA"
[1] => string(4) "0xAA"
[2] => int(170)
[3] => string(1) "1"
[4] => int(1)
[5] => int(0)
[6] => string(1) "0"

Risultati del test

Valore Risultato desiderato ereg('[0-9]{1,5}', $int) ereg('^[0-9]{1,5}$', $int) is_numeric() is_int() $int + 0 intval($int) (bool) intval($int) ctype_digit($int)
string(2) "AA" bool(false) bool(false) bool(false) bool(false) bool(false) int(0) int(0) bool(false) bool(false)
string(4) "0xAA" bool(false) bool(true) bool(false) bool(true) bool(false) int(170) int(0) bool(false) bool(false)
int(170) bool(true) bool(true) bool(true) bool(true) bool(true) int(170) int(170) bool(true) bool(false)
string(1) "1" bool(true) bool(true) bool(true) bool(true) bool(false) int(1) int(1) bool(true) bool(true)
int(1) bool(true) bool(true) bool(true) bool(true) bool(true) int(1) int(1) bool(true) bool(false)
int(0) bool(false) bool(true) bool(true) bool(true) bool(true) int(0) int(0) bool(false) bool(false)
string(1) "0" bool(false) bool(true) bool(true) bool(true) bool(false) int(0) int(0) bool(false) bool(true)

Le soluzioni ottimali sono quindi principalmente tre, a dipendenza dalle diverse necessità:

  1. ereg('^[0-9]{1,5}$', $int)
  2. (bool) intval($int)
  3. ctype_digit($int)

La soluzione che contempla l'uso di un'espressione regolare ha come vantaggio un controllo più immediato della lunghezza minima e massima dell'intero e contempla anche il caso in cui l'id abbia un valore numerico 0.

La soluzione basata sulla conversione di tipo risulterà più performante ma non eseguirà nessun controllo sulla lunghezza dell'intero. Al contrario della soluzione basata sulla regex, questa soluzione esclude per sua natura il caso in cui l'id abbia un valore 0, il che potrebbe rappresentare anche un vantaggio.
Infatti, il valore degli id all'interno di tabelle di Database relazionali solitamente è rappresentato con un intero positivo diverso da 0.

Se invece si possono avere id con valore 0 e si deve eseguire il controllo solamente su dati di tipo stringa, la soluzione migliore è sicuramente quella basata su ctype_digit.

Tutte le soluzioni possono comunque essere facilmente combinate per adeguarsi a qualsiasi controllo numerico

Codice php

<?php // is_numeric.php

include 'is_numeric.inc.php';

$number = array(
    array(
'AA'false),
    array(
'0xAA'false),    // Assegno un numero esadecimale come stringa
    
array(0xAAtrue),        // Assegno un numero esadecimale come intero
    
array('1'true),
    array(
1true),
    array(
0false),
    array(
"0"false)
);
?>

<h1>Test su interi e loro comportamento</h1>

<h2>Valori usati per il test</h2>
<pre>
<?php foreach ($number as $i => $int): ?>
[<?php echo $i ?>] => <?php var_dump($int[0]) ?>
<?php 
endforeach; ?>
</pre>


<h2>Risultati del test</h2>

<table cellspacing="3">
    <tr>
        <th>Valore</th>
        <th>Risultato desiderato</th>
        <th>ereg('[0-9]{1,5}', $int)</th>
        <th>ereg('^[0-9]{1,5}$', $int)</th>
        <th>is_numeric()</th>
        <th>is_int()</th>
        <th>$int + 0</th>
        <th>intval($int)</th>
        <th>(bool) intval($int)</th>
        <th>ctype_digit($int)</th>
    </tr>

    <?php foreach ($number as $int): ?>
    <tr>
        <?php getInfo($int?>
    </tr>
    <?php endforeach; ?>

</table>

<?php // is_numeric.inc.php

function getInfo($int)
{
    
dump($int[0]);
    
dump($int[1]);
    
dump((bool) ereg('[0-9]{1,5}'$int[0]));
    
dump((bool) ereg('^[0-9]{1,5}$'$int[0]));
    
dump(is_numeric($int[0]));
    
dump(is_int($int[0]));
    
dump($int[0] + 0);
    
dump(intval($int[0]));
    
dump((bool) intval($int[0]));
    
dump(ctype_digit($int[0]));
}

function 
dump($text)
{
    if (
$text === true) {
        
$class 'true';
    } else if (
$text === false) {
        
$class 'false';
    } else {
        
$class '';
    }
    
    echo 
"<td class=\"$class\">";
    
var_dump($text);
    echo 
"</td>";
}