0

PHP – typy danych, typy proste [Podstawy programowania]

Typowanie (typy danych) w języku PHP

Myli się ten, kto twierdzi, że w PHPie nie istnieją typy danych albo że w PHPie nie ma typowania. Jest to język programowania, który używa typowania słabego, co jednak wcale nie znaczy, że nie występują w nim typy danych. W pewnych sytuacjach możemy kontrolować typ zmiennych i wykorzystywać go do naszych celów. Jest to zachowanie całkowicie różne od tego znanego przykładowo z języków C / C++, więc warto je poznać (a nie tylko poprzestać na przypuszczeniach) jeśli chcemy tworzyć strony internetowe w języku PHP.

Dokumentacja PHP wyróżnia 8 prymitywów (z czego pewnie na miano typów prostych zasługują 4 pierwsze):

  • boolean,
  • integer,
  • float,
  • string,
  • array,
  • object,
  • callable,
  • resource,
  • NULL.

Warto dodać, że nie występuje tutaj oddzielny typ double (jeśli już to jest to synonim (alias) typu float). Nie ma też typu char (zazwyczaj będzie on rozumiany jako string, ewentualnie jako integer). Rozmiar i zakres typów danych jest zależny od środowiska i wersji serwera. Jak go sprawdzić? Dla integera mamy zdefiniowane stałe pokazane w poniższym kodzie. Dla stringa możemy próbować korzystać z funkcji strlen. Nie ma jednak prostego i dokładnego rozwiązania dla pozostałych typów danych. Można obliczyć przybliżoną wartość używając „tricków”, ale przecież nie o to tutaj chodzi…

<?php
   echo "PHP_INT_SIZE: ".  PHP_INT_SIZE . "\n";
   echo "PHP_INT_MIN: ".  PHP_INT_MIN . "\n";
   echo "PHP_INT_MAX: ".  PHP_INT_MAX . "\n\n";

 

Sprawdzanie typów zmiennych

W zasadzie nie możemy deklarować jakiego typu ma być nasza zmienna. Typ jest zmieniany w zależności od zawartości i kontekstu. Możemy go jednak sprawdzać i w ten sposób wykonywać tylko operacje przeznaczone dla konkretnego typu danych.

<?php
   
    echo(gettype(0)); // integer
    echo(gettype("a")); // string
    echo(gettype(1.0)); // double === float
    
    // zmienna może zmieniać swój typ w trakcie wykonywania skryptu
    // przykład tzw. żonglowania typami
    
    $a = 0;         // integer
    if (is_int($a)) // TRUE
        echo($a);   // integer
     
    $a = 'a';       // string
    if (is_int($a)) // FALSE
        echo($a);   // string

Dla programisty PHP niezbędna jest również znajomość tabeli porównań, gdyż nie zawsze jest ona oczywista. Jak zawsze można ją znaleźć na odpowiedniej stronie dokumentacji.

Zmiana typu danych

W języku PHP możemy zmieniać typy zmiennych. Do osiągnięcia tego celu można użyć funkcji settype() lub rzutowania (które działa podobnie jak w przypadku C++).  Do wyboru mamy jednak trochę więcej możliwości, a dokładnie:

  • (int), (integer) – rzutowanie na integer,
  • (bool), (boolean) – rzutowanie na boolean,
  • (float), (double), (real) – rzutowanie na float,
  • (string) – rzutowanie na string,
  • (array) – rzutowanie na array,
  • (object) – rzutowanie na object,
  • (unset) – rzutowanie na NULL (PHP 5),
  • (binary) – rzutowanie na binary string (od PHP 5.2.1).
<?php
 
 $a = 10;                   // integer
 settype($a, 'string');     // zmiana na typ string
 echo gettype($a);          // string
 
 echo $a * 2;               // 10 -- $a jest automatycznie konwertowane do typu integer
 
 echo gettype( (float) $a); // double; rzutowanie na typ float (float === double)
 
 $b = 20;                   // integer
 echo gettype("$b");        // string; rzutowanie na string
 echo gettype((string) $b); // string; rzutowanie na string (jest to równoważne powyższej linii)

Jeśli chodzi o konwersję z typu string na integer to zawsze, jeśli będzie tego wymagał kontekst, odbędzie się taka próba. Jeśli na początku stringa będzie się znajdować liczba i będzie się ona mieściła w zakresie typu to rzutowanie się powiedzie, w innym wypadku wartość takiego rzutowania wyniesie 0.

Stringi

Zdaje się, że PHP traktuje stringi jako typ prosty, a więc jestem zobligowany do napisania czegoś więcej na ich temat. Przypisywanie stringa do zmiennej może się odbywać co najmniej na 3 sposoby:

  • za pomocą apostrofów (zmienne i sekwencje ucieczki (np. \n, \r) nie będą interpretowane tylko wyświetlone jako tekst (za wyjątkiem \’ oraz \\):
    <?php 
    
    $str = 'Przykład stringa
    z wieloma liniami';
    
  • za pomocą cudzysłowów (zmienne i sekwencje ucieczki będą interpretowane – nie dotyczy stałych i pól statycznych):
    <?php
    
    $str = "Przykład stringa
    z wieloma liniami
    oraz $zmienna";
  •  za pomocą operatora Heredoc (zachowuje się analogicznie jak cudzysłów):
    <?php
    
    $str = <<<SZALONYPECET
    Szalony Pecet jest najlepszą
    stroną informatyczną w kraju.
    Można na niej znaleźć wiele 
    ciekawych informacji, porad,
    opinii i newsów!
    SZALONYPECET;

String w PHP od wersji 7.0 nie ma narzuconego ograniczenia rozmiaru. Zawiera jednak tylko znaki ASCII, a więc czasem używanie znaków Unicode może wymagać większej uwagi i konieczne jest stosowanie funkcji multi byte. Można jednak traktować stringi jako tablice i odnosić się do ich elementów za pomocą nawiasów kwadratowych i klamrowych:

<?php

$str = "Szalony Pecet";
echo $str[0] . $str{1}; // Sz

Referencje

W PHP domyślnie zmienne przekazywane są przez wartość. Można jednak zmienić to zachowanie poprzez zastosowanie operatora &. Przy jego użyciu zmienne przekazywane są przez referencję, np.

<?php

function fun(&$s){
    $s .= "Pecet";
}

$str = "Szalony ";

fun($str);
echo $str; // Szalony Pecet

Deklaracja typów w argumentach funkcji (type declarations / type hints)

Przede wszystkim od wersji 7.0 PHP jesteśmy w stanie tworzyć funkcje, które przyjmują parametry określonych typów (od wersji 5.0 było to możliwe tylko dla klas oraz self, następnie m. in. dla tablic).

<?php

class SzalonyPecet {
    
    function a (int $count){
        echo "Szalony Pecet jest super";
        for($i=0; $i<$count; $i++){
            echo "!";
        }
    }
    
    function b(SzalonyPecet $szalonyPecet){
        return TRUE;
    }
    
}

$str = "aaa";

$sp = new SzalonyPecet();
$sp->a($str);               // Fatal error
$sp->a(5);                  // OK
$sp->b(5);                  // Fatal error
$sp->b(new SzalonyPecet()); // OK

 

Ciekawostki

Wydaje mi się, że w językach o słabym typowaniu więcej jest niespodzianek dla programisty. Dlatego tak ważna jest bardzo dobra znajomość wyżej wspomnianego materiału. Poniżej przedstawiam ciekawostki związane z typowaniem, które czasem są sprzeczne ze zdrowym rozsądkiem.

<?php

$a = 0123;  // zapis w systemie 8-kowym (!)
echo $a;    // 83
echo "\n";

$a = "0123"; 
echo (int) $a; // 123
echo "\n";

$b = TRUE; 
echo "$b"; // TRUE
echo "\n";

$b = FALSE; 
echo "$b"; // ???
echo "\n";

$c = 0;
if(empty($c)){ // empty() zwraca TRUE dla zera
    echo 'Zmienna $c jest pusta... ale ma wartość: ' . $c;
    echo "\n";
}

$d = 0;
if ($d){     // bardzo często spotykana konstrukcja (zwraca FALSE m. in. dla zera)
    echo $d; 
    echo "\n";
}

if (NULL == ""){ 
    echo "NULL == \"\"";
    echo "\n";
}

if (array() == FALSE){
    echo "array() == FALSE";
    echo "\n";
}

if (5 == 5.){           // żonglowanie typami
    echo "5 == 5.";
    echo "\n";
}

if ((int)5 == (float)5.){ // z rzutowaniem trzeba postępować ostrożnie
    echo "(int)5 == (float)5.";
    echo "\n";
}

if (NULL <= -1){
    echo "NULL <= -1";
    echo "\n";
}

if ("test" == 0){        // automatyczne rzutowanie na integer
    echo '"test" == 0';
    echo "\n";
}

Podsumowanie

Wbrew obiegowej opinii język PHP zawiera typy danych. Nie jest ich wiele i czasem mogą prowadzić do nieporozumień, ale istnieją i można je modyfikować według potrzeb. W dodatku nowe wersje PHP wprowadzają możliwość żądania konkretnego typu danych w metodach/funkcjach, co pozwoli nie wykonywać dodatkowej walidacji (szczególnie przy włączonym strict mode), a także przyczyni się do zmniejszenia ilości błędów w aplikacjach PHP spowodowanych złym typowaniem. Tak jak już kiedyś pisałem moim zdaniem PHP zmierza w kierunku wyznaczonym przez język Hack, którego najważniejszą różnicą w stosunku do PHP jest silne typowanie. Ważne jednak jest, żeby programiści używający języka PHP zdawali sobie sprawę z tego w jaki sposób działa słabe typowanie i jakie korzyści można w ten sposób osiągnąć.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *