3. Podstawy PHP
3.1. Struktura drzewa skryptów

3.2. Konfiguracja PHP
PHP jest wstępnie skonfigurowany za pomocą pliku tekstowego [php.ini]. Wszystkie te ustawienia można zmienić programowo. Konfiguracja PHP ma duży wpływ na działanie skryptów. Dlatego ważne jest, aby ją znać. Umożliwia to następujący skrypt [phpinfo.php]:
Komentarze
- wiersz 3: funkcja [phpinfo] wyświetla konfigurację PHP;
Wyniki wykonania
Funkcja [phpinfo] wyświetla tutaj ponad 800 wierszy konfiguracyjnych. Nie będziemy ich omawiać, ponieważ większość z nich dotyczy zaawansowanego wykorzystania funkcji PHP. Ważnym wierszem jest wiersz 13 powyżej: wskazuje on, który plik [php.ini] został użyty do skonfigurowania pliku PHP, którego będziesz używać do uruchamiania swoich skryptów. Jeśli chcesz zmienić konfigurację uruchamiania pliku PHP, to właśnie ten plik musisz zmodyfikować. W pliku tym znajduje się wiele komentarzy wyjaśniających rolę poszczególnych ustawień.
3.3. Pierwszy przykład
3.3.1. Kod
Poniżej znajduje się program [bases-01.php], który prezentuje podstawowe cechy programu PHP.
<?php
// to jest komentarz
// zmienna użyta bez zadeklarowania
$nom = "dupont";
// wyświetlanie na ekranie
print "nom=$nom\n";
// tablica zawierająca elementy różnych typów
$tableau = array("un", "deux", 3, 4);
// liczba elementów
$n = count($tableau);
// pętla
for ($i = 0; $i < $n; $i++) {
print "tableau[$i]=$tableau[$i]\n";
}
// inicjalizacja dwóch zmiennych zawartością tablicy
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// konkatenacja dwóch ciągów znaków
$chaine3 = $chaine1 . $chaine2;
// wyświetlenie wyniku
print "[$chaine1,$chaine2,$chaine3]\n";
// użycie funkcji
affiche($chaine1);
// typ zmiennej może być znany
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// typ zmiennej może ulec zmianie w trakcie wykonywania
$n = "a changé";
afficheType("n", $n);
// funkcja może zwracać wynik
$res1 = f1(4);
print "res1=$res1\n";
// funkcja może zwracać tablicę wartości
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// wartości te można by było pobrać do tablicy
$t = f2();
for ($i = 0; $i < count($t); $i++) {
print "t[$i]=$t[$i]\n";
}
// testy
for ($i = 0; $i < count($t); $i++) {
// wyświetla tylko ciągi znaków
if (getType($t[$i]) === "string") {
print "t[$i]=$t[$i]\n";
}
}
// operatory porównania == i ===
if("2"==2){
print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// inne testy
for ($i = 0; $i < count($t); $i++) {
// wyświetla tylko liczby całkowite >10
if (getType($t[$i]) === "integer" and $t[$i] > 10) {
print "t[$i]=$t[$i]\n";
}
}
// pętla while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
print "t[$i]=$t[$i]\n";
$somme += $t[$i]; //$somme=$somme+$t[$i]
$i++; //$i=$i+1
}//while
print "somme=$somme\n";
// koniec programu
exit;
//----------------------------------
function affiche($chaine) {
// wyświetla $chaine
print "chaine=$chaine\n";
}
//wyświetla
//----------------------------------
function afficheType($name, $variable) {
// wyświetla typ $variable
print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}
//afficheType
//----------------------------------
function f1($param) {
// dodaje 10 do $param
return $param + 10;
}
//----------------------------------
function f2() {
// zwraca 3 wartości
return array("un", 0, 100);
}
?>
Wyniki:
nom=dupont
tableau[0]=un
tableau[1]=deux
tableau[2]=3
tableau[3]=4
[chaine1,chaine2,chaine1chaine2]
chaine=chaine1
type[variable $n]=integer
type[variable $chaine1]=string
type[variable $tableau]=array
type[variable $n]=string
res1=14
(res1,res2,res3)=[un,0,100]
t[0]=un
t[1]=0
t[2]=100
t[0]=un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[2]=100
t[0]=8
t[1]=5
somme=13
Komentarze
- wiersz 5: w programie PHP nie deklaruje się typów zmiennych. Mają one typ dynamiczny, który może się zmieniać w trakcie działania programu. $nom oznacza zmienną o identyfikatorze „nom”;
- wiersz 7: aby wyświetlić dane na ekranie, można użyć instrukcji print lub instrukcji echo;
- wiersz 9: słowo kluczowe array pozwala zdefiniować tablicę. Zmienna $nom[$i] reprezentuje element $i tablicy $tableau;
- wiersz 11: funkcja count($tableau) zwraca liczbę elementów tablicy $tableau;
- wiersze 13–15: pętla. Ponieważ zawiera ona tylko jedną instrukcję, nawiasy klamrowe są w tym przypadku opcjonalne. W dalszej części niniejszego dokumentu będziemy konsekwentnie stosować nawiasy klamrowe niezależnie od liczby instrukcji;
- wiersz 14: ciągi znaków są ujęte w cudzysłowy „ lub apostrofy '. Wewnątrz cudzysłowów zmienne $variable są obliczane, ale nie w apostrofach;
- wiersz 17: funkcja list pozwala zebrać zmienne w liście i przypisać im wartość za pomocą jednej operacji przypisania. Tutaj $chaine1="ciąg1" oraz $chaine2="ciąg2";
- wiersz 19: operator . służy do konkatenacji ciągów znaków;
- wiersze 83–86: słowo kluczowe function definiuje funkcję. Funkcja zwraca lub nie zwraca wartości za pomocą instrukcji return. Kod wywołujący może zignorować lub pobrać wyniki funkcji. Funkcję można zdefiniować w dowolnym miejscu kodu.
- wiersz 92: predefiniowana funkcja getType($variable) zwraca ciąg znaków reprezentujący typ $variable. Typ ten może ulegać zmianom w czasie;
- wiersz 45: operator === porównuje dwa elementy w sposób ścisły: aby można je było porównać, muszą mieć ten sam typ. Operator == jest mniej ścisły: dwa elementy mogą być równe, nie będąc tego samego typu. Pokazują to instrukcje w wierszach 50–60. W przypadku operatora == porównanie odbywa się po przekształceniu obu porównywanych elementów do tego samego typu. Następują wówczas domyślne konwersje. Dość łatwo jest „zapomnieć” o obecności tych domyślnych konwersji i w ten sposób uzyskać nieprzewidziane wyniki, takie jak stwierdzenie, że warunek jest prawdziwy, podczas gdy oczekiwano, że będzie fałszywy. Aby uniknąć tej pułapki, będziemy konsekwentnie stosować operator porównania ===;
- wiersz 64: można również używać operatorów boolowskich or i !;
- wiersz 69: zamiast notacji array() można użyć notacji [] do zainicjowania tablicy z funkcji PHP7;
- wiersz 80: predefiniowana funkcja exit zatrzymuje wykonywanie skryptu;
- wiersz 107: tag ?> sygnalizuje koniec skryptu PHP. Nie jest on niezbędny. Ponadto w kontekście internetowym może ona stanowić problem, jeśli po niej następują spacje lub znaki końca linii, które są trudne do wykrycia, ponieważ nie są widoczne w edytorze tekstu. Dlatego w dalszej części dokumentu będziemy systematycznie pomijać ten znacznik;
Uwaga: w niniejszym dokumencie będziemy używać słowa kluczowego [print] do wyświetlania tekstu na konsoli. Inną metodą osiągnięcia tego samego celu jest użycie słowa kluczowego [echo]. Istnieją subtelne różnice między tymi dwoma słowami kluczowymi, ale w kontekście niniejszego dokumentu nie będą one miały żadnego znaczenia. Jeśli więc wolisz używać słowa kluczowego [echo], to śmiało.
3.3.2. Korzystanie z NetBeans
NetBeans wyświetla różne ostrzeżenia, które warto sprawdzić. Weźmy na przykład skrypt [bases-01.php]:

W wierszu 5 NetBeans wyświetla ostrzeżenie, że plik nie jest zgodny z zaleceniem PSR-1 (PHP Standard Recommendations nr 1). Zalecenia PSR mają na celu tworzenie standardowego kodu, co ułatwia współdziałanie i konserwację kodu napisanego przez różne osoby. Otrzymywanie ostrzeżeń może być uciążliwe, jeśli celowo chce się odstąpić od standardów, na przykład dlatego, że zespół projektowy stosuje inne. To, co chcemy sprawdzać, a czego nie, w NetBeans, można skonfigurować:

- w [5] znajdują się elementy, które chcemy sprawdzać za pomocą NetBeans;
- w [6] – poziom ważności przypisany do błędu zgłoszonego przez NetBeans;

W pliku [7] widać, że zlecono sprawdzenie, czy kod jest zgodny z zaleceniami PSR-0 i PSR-1. Nie ma tu żadnych obowiązkowych wymagań. Na etapie nauki języka zaleca się sprawdzanie jak największej liczby opcji oferowanych przez NetBeans. W ten sposób można się wiele nauczyć. Następnie dostosujemy te ustawienia sprawdzania w NetBeans do standardów kodowania obowiązujących w zespole projektowym.
Przyjrzyjmy się standardom kodowania PSR-1 i [8, 9]:
Opcja | Sprawdzanie |
| Stałe klasowe MUST powinny być deklarowane wielkimi literami z separatorami w postaci znaków podkreślenia. Np.: const TAUX_TVA |
| Nazwy metod MUST należy deklarować w metodzie camelCase(). Przykład: public function executeBatchImpots{} |
| Nazwy właściwości SHOULD należy zadeklarować w pliku $StudlyCaps, $camelCase lub $under_score (spójnie w jednym zakresie) Np.: public SalaireAnnuel (StudlyCaps), public salaireAnnuel (camelCase), public salaire_annuel (under_score) |
| Plik SHOULD deklaruje nowe symbole i nie powoduje żadnych innych skutków ubocznych, natomiast plik SHOULD wykonuje logikę powodującą skutki uboczne, a pliki SHOULD i NOT robią jedno i drugie. |
| Nazwy typów MUST należy zadeklarować w StudlyCaps (Kod napisany dla wersji 5.2.x i wcześniejszych SHOULD stosuje konwencję pseudoprzestrzeni nazw polegającą na dodawaniu prefiksów Vendor_ do nazw typów). Każdy typ znajduje się w osobnym pliku i należy do przestrzeni nazw o co najmniej jednym poziomie: nazwy dostawcy na najwyższym poziomie. Przykład: class EtudiantBoursier {} |
Zalecenie PSR-1 / 4 stanowi, że w pliku PHP musi znajdować się:
- albo deklarację typu (klasy, interfejs);
- albo kod wykonywalny bez deklaracji nowych typów;
Istnieją inne zalecenia PHP, które nie są sprawdzane przez NetBeans: PSR-3, PSR-4, PSR-6, PSR-7 oraz PSR-13.
Ze względu na wygodę nie we wszystkich przykładach zawartych w niniejszym dokumencie sprawdzono zalecenie PSR-1, ponieważ wymaga to rozdzielenia kodu klas i interfejsów do oddzielnych plików, co jest zbyt uciążliwe w przypadku podstawowych przykładów. Łatwiej jest zatem umieścić wszystko w jednym pliku. W przypadku przykładowej aplikacji, która stanowi motyw przewodni niniejszego dokumentu, starano się jak najlepiej przestrzegać zalecenia PSR-1.
Niektóre ostrzeżenia programu NetBeans sygnalizują potencjalny błąd:

Ostrzeżenie [Unitialized Variables] sygnalizuje prawdopodobny błąd, często wynikający z literówki w nazwie zmiennej. To samo dotyczy ostrzeżenia [Unused Variables].
Wreszcie zaleca się sprawdzenie wszystkich ostrzeżeń programu NetBeans sygnalizowanych paskiem na lewym marginesie kodu oraz żółtą kreską na prawym marginesie:


3.4. Zakres zmiennych
3.4.1. Przykład 1
Skrypt [bases-02.php] wygląda następująco:
<?php
// zakres zmiennych
function f1() {
// używa się zmiennej globalnej $i
global $i;
$i++;
$j = 10;
print "f1[i,j]=[$i,$j]\n";
}
function f2() {
// używana jest zmienna globalna $i
global $i;
$i++;
$j = 20;
print "f2[i,j]=[$i,$j]\n";
}
function f3() {
// używana jest zmienna lokalna $i
$i = 4;
$j = 30;
print "f3[i,j]=[$i,$j]\n";
}
// testy
$i = 0;
$j = 0; // te dwie zmienne nie są znane funkcji f
// tylko wtedy, gdy funkcja ta jawnie zadeklaruje je za pomocą instrukcji global
// że zamierza z nich korzystać
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";
Wyniki:
Komentarze
- wiersze 29–30: definiują dwie zmienne $i i $j w programie głównym. Zmienne te nie są rozpoznawane wewnątrz funkcji. Tak więc w wierszu 9 zmienna $j z funkcji f1 jest zmienną lokalną funkcji f1 i różni się od zmiennej $j z programu głównego. Funkcja może uzyskać dostęp do zmiennej $variable z programu głównego za pomocą słowa kluczowego global;
- w wierszu 7 instrukcja odnosi się do zmiennej globalnej $i z programu głównego;
3.4.2. Przykład 3
Skrypt [bases-03.php] ma następującą postać:
<?php
// zakres zmiennej jest globalny w stosunku do bloków kodu
$i = 0; {
$i = 4;
$i++;
}
print "i=$i\n";
Wyniki:
Komentarze
W niektórych językach zmienna zdefiniowana w nawiasach klamrowych ma zasięg ograniczony do tych nawiasów: nie jest ona znana poza nimi. Powyższe wyniki pokazują, że w języku PHP tak nie jest. Zmienna $i zdefiniowana w linii 5 wewnątrz nawiasów klamrowych jest tą samą zmienną, co ta użyta w liniach 4 i 8 poza nimi.
3.5. Zmiany typów
Zmienne w PHP nie mają stałego typu. Typ ten może zmieniać się w trakcie wykonywania w zależności od wartości przypisanej do zmiennej. W operacjach obejmujących dane różnych typów interpreter PHP dokonuje domyślnych konwersji, aby sprowadzić operandy do wspólnego typu. Te domyślne konwersje, jeśli nie są znane programiście, mogą być źródłem trudnych do wykrycia błędów. Poniżej przedstawiono skrypt [bases-04.php] pokazujący konwersje domyślne i jawne:
<?php
// ścisłe typy przy przekazywaniu parametrów
declare(strict_types=1);
// domyślne zmiany typów
// typ -->bool
print "Conversion vers un booléen------------------------------\n";
showBool("abcd", "abcd");
showBool("", "");
showBool("[1, 2, 3]", [1, 2, 3]);
showBool("[]", []);
showBool("NULL", NULL);
showBool("0.0", 0.0);
showBool("0", 0);
showBool("4.6", 4.6);
function showBool(string $prefixe, $var) : void {
print "(bool) $prefixe : ";
// konwersja $var na wartość logiczną odbywa się automatycznie w następującym po niej teście
if ($var) {
print "true";
} else {
print "false";
}
print "\n";
}
Komentarze
- wiersz 4: wymaga ścisłej weryfikacji typu parametrów funkcji, gdy jest on określony;
- wiersz 18: funkcja [showBool] ma na celu pokazanie niejawnej (automatycznej) transformacji, jaką wykonuje interpreter PHP, gdy wartość dowolnego typu musi zostać przekształcona na wartość logiczną (wiersz 21);
- wiersz 18: parametrowi $var nie przypisano typu. Rzeczywisty parametr może zatem być dowolnego typu. Natomiast parametr $prefixe musi być typu string. Funkcja showBool nie zwraca żadnej wartości (void);
- wiersz 21: w instrukcji if($var) wartość $var musi zostać przekształcona na wartość logiczną, aby można było obliczyć wartość if. Co zaskakujące, interpreter PHP zwraca wynik niezależnie od typu przekazanej mu wartości;
- wiersze 9–16: wartość parametru funkcji [showBool] będzie kolejno:
- wiersz 9: ciąg znaków niepusty: wynik TRUE (wielkość liter nie ma znaczenia, TRUE = true);
- wiersz 10: pusty ciąg znaków: wynik FALSE;
- wiersz 11: niepusta tablica: wynik TRUE;
- wiersz 12: tablica pusta: wynik FALSE;
- wiersz 14: liczba rzeczywista 0: wynik FALSE;
- wiersz 15: liczba całkowita 0: wynik FALSE;
- wiersz 16: liczba rzeczywista (lub całkowita) różna od 0: wynik TRUE;
Widać to na poniższych zrzutach ekranu:
Conversion vers un booléen------------------------------
(bool) abcd : true
(bool) : false
(bool) [1, 2, 3] : true
(bool) [] : false
(bool) NULL : false
(bool) 0.0 : false
(bool) 0 : false
(bool) 4.6 : true
Kontynuujmy kod skryptu:
//
// domyślne zmiany typu z ciągu znaków na typ liczbowy
// ciąg znaków --> liczba
print "Conversion chaîne vers nombre------------------------------\n";
showNumber("12");
showNumber("45.67");
showNumber("abcd");
function showNumber(string $var) : void {
$nombre = $var + 1;
var_dump($nombre);
print "($var): $nombre\n";
}
Komentarze
- wiersz 9: funkcja [showNumber] przyjmuje parametr typu string i nie zwraca wyniku (void);
- wiersz 10: parametr ten jest wykorzystywany w operacji arytmetycznej, co zmusi interpreter PHP do próby przekształcenia $var w liczbę;
- wiersz 5: przekształci ciąg znaków „12” w liczbę całkowitą 12;
- wiersz 6: przekształci ciąg znaków „45.67” w liczbę rzeczywistą 45.67;
- wiersz 7: wyświetli ostrzeżenie, ale mimo to przekształci ciąg znaków „abcd” w liczbę 0;
Oto wyniki wykonania:
Kontynuujmy kod skryptu:
// jawne zmiany typu
// na int
showInt("12.45");
showInt(67.8);
showInt(TRUE);
showInt(NULL);
function showInt($var) : void {
print "paramètre : ";
var_dump($var);
print "\n";
print "résultat de la conversion : ";
var_dump((int) $var);
print "\n";
}
Komentarze
- wiersz 21: funkcja [showInt] przyjmuje parametr dowolnego typu i nie zwraca wyniku. Próbuje przekonwertować parametr $var na liczbę całkowitą w wierszu 26. Ogólnie rzecz biorąc, aby zmienić zmienną $var na typ T, pisze się (T) $var, gdzie T może być: int, integer, bool, boolean, float, double, real, string, array, object, unset;
- wiersz 16: konwertuje ciąg znaków „12.45” na liczbę całkowitą 12;
- wiersz 17: konwertuje liczbę rzeczywistą 67,8 na liczbę całkowitą 67;
- wiersz 18: konwertuje wartość logiczną TRUE na liczbę całkowitą 1 (wartość logiczną FALSE na liczbę całkowitą 0);
- wiersz 19: konwertuje wskaźnik NULL na liczbę całkowitą 0;
Tak to widać na zrzutach ekranu:
Kontynuujemy analizę skryptu, przechodząc do jawnej konwersji wartości na typ float:
// na float
showFloat("12.45");
showFloat(67);
showFloat(TRUE);
showFloat(NULL);
function showFloat($var) : void {
print "paramètre : ";
var_dump($var);
print "\n";
print "résultat de la conversion : ";
var_dump((float) $var);
print "\n";
}
Komentarze
- wiersz 35: funkcja [showFloat] przyjmuje parametr dowolnego typu i nie zwraca wyniku;
- wiersz 40: wartość tego parametru jest jawnie przekształcana na float;
- wiersz 30: ciąg znaków „12.45” jest przekształcany na liczbę rzeczywistą 12.45;
- wiersz 31: liczba całkowita 67 jest przekształcana na liczbę rzeczywistą 67;
- wiersz 32: wartość logiczna TRUE jest przekształcana na liczbę rzeczywistą 1 (wartość FALSE na liczbę 0);
- wiersz 33: wskaźnik NULL jest przekształcany na liczbę rzeczywistą 0;
Tak wyglądają wyniki wyświetlane na ekranie:
Kontynuujemy omówienie skryptu, analizując konwersje na typ string:
// na ciąg znaków
showstring(5);
showString(6.7);
showString(FALSE);
showString(NULL);
function showString($var) : void {
print "paramètre : ";
var_dump($var);
print "\n";
print "résultat de la conversion : ";
var_dump((string) $var);
print "\n";
}
- wiersz 49: funkcja [showString] przyjmuje parametr dowolnego typu i nie zwraca wyniku;
- wiersz 54: wartość parametru jest przekształcana na typ string;
- wiersz 44: liczba całkowita 5 zostanie przekształcona w ciąg znaków „5”;
- wiersz 45: liczba rzeczywista 6,7 zostanie przekształcona w ciąg znaków „6,7”;
- wiersz 46: wartość logiczna FALSE zostanie przekształcona w pusty ciąg znaków;
- wiersz 47: wskaźnik NULL zostanie przekształcony w pusty ciąg znaków;
Oto wyniki wyświetlane na ekranie:
3.6. Tablice
3.6.1. Klasyczne tablice jednowymiarowe
Skrypt [bases-05.php] wygląda następująco:
<?php
// klasyczne tablice
// inicjalizacja
$tab1 = array(0, 1, 2, 3, 4, 5);
// przeglądanie – 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// przeglądanie – 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1)) {
print "tab1[$clé]=$valeur\n";
}
// dodawanie elementów
$tab1[] = $i++;
$tab1[] = $i++;
// przeglądanie – 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
print "tab1[$i]=$élément\n";
$i++;
}
// usunięcie ostatniego elementu
array_pop($tab1);
// przeglądanie – 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// usunięcie pierwszego elementu
array_shift($tab1);
// przeglądanie – 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// dodanie na końcu tablicy
array_push($tab1, -2);
// przeglądanie – 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// dodanie na początku tablicy
array_unshift($tab1, -1);
// przeglądanie – 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
Wyniki:
tab1 a 6 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 6 éléments
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_04.php on line 14
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 8 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=7
tab1 a 7 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1 a 6 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1 a 7 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1[6]=-2
tab1 a 8 éléments
tab1[0]=-1
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=-2
Komentarze
Powyższy program przedstawia operacje na tablicy wartości. W skrypcie PHP istnieją dwa sposoby zapisu tablic:
Tablica 1 nazywana jest tablicą, a tablica 2 – słownikiem lub tablicą asocjacyjną, w której elementy są zapisywane w postaci klucz => wartość. Notacja $contraires["beau"] oznacza wartość powiązaną z kluczem „piękny”. W tym przypadku jest to więc ciąg znaków „brzydki”. Tablica 1 jest jedynie odmianą słownika i mogłaby być zapisana jako:
W ten sposób otrzymujemy $tableau[2] = „trois”. Ostatecznie istnieją wyłącznie słowniki. W przypadku klasycznej tablicy zawierającej n elementów klucze stanowią liczby całkowite z przedziału [0,n-1].
- wiersz 14: funkcja each($tableau) pozwala na iterację po słowniku. Przy każdym wywołaniu zwraca ona parę (klucz, wartość) z tego słownika. Jak pokazuje wiersz 10 wyników, funkcja each jest obecnie przestarzała w PHP 7;
- wiersz 13: funkcja reset($dictionnaire) ustawia funkcję each na pierwszą parę (klucz, wartość) w słowniku.
- wiersz 14: pętla while kończy się, gdy funkcja each zwraca pustą parę na końcu słownika. W tym przypadku ma miejsce konwersja domyślna: pusta para jest konwertowana na wartość logiczną FALSE;
- wiersz 18: zapis $tableau[]=wartość dodaje element valeur jako ostatni element tablicy $tableau;
- wiersz 23: tablica jest przeglądana za pomocą foreach. Ten element składniowy pozwala na przeglądanie słownika, a więc tablicy, zgodnie z dwiema składniami:
Pierwsza składnia zwraca parę (clé,valeur) przy każdej iteracji, podczas gdy druga zwraca jedynie element valeur ze słownika.
- wiersz 28: funkcja array_pop($tableau) usuwa ostatni element z $tableau;
- wiersz 35: funkcja array_shift($tableau) usuwa pierwszy element z $tableau;
- wiersz 42: funkcja array_push($tableau, wartość) dodaje valeur jako ostatni element do $tableau;
- wiersz 49: funkcja array_unshift($tableau, wartość) dodaje valeur jako pierwszy element do $tableau;
3.6.2. Słownik lub tablica asocjacyjna
Skrypt [bases-06.php] wygląda następująco:
<?php
// słowniki
$conjoints = ["Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => ""];
// przeglądanie – 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
print "conjoints[$clé]=$valeur\n";
}
// sortowanie słownika według klucza
ksort($conjoints);
// przeglądanie – 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
print "conjoints[$clé]=$valeur\n";
}
// lista kluczy słownika
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++) {
print "clés[$i]=$clés[$i]\n";
}
// lista wartości słownika
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++) {
print "valeurs[$i]=$valeurs[$i]\n";
}
// wyszukiwanie klucza
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// usunięcie pary klucz-wartość
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
print "conjoints[$clé]=$valeur\n";
}
// koniec
exit;
function existe($conjoints, $mari) {
// sprawdza, czy klucz $mari istnieje w słowniku $conjoints
if (isset($conjoints[$mari])) {
print "La clé [$mari] existe associée à la valeur [$conjoints[$mari]]\n";
} else {
print "La clé [$mari] n'existe pas\n";
}
}
Wyniki:
Nombre d'éléments du dictionnaire : 4
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_05.php on line 8
conjoints[Pierre]=Gisèle
conjoints[Paul]=Virginie
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
clés[0]=Jacques
clés[1]=Jean
clés[2]=Paul
clés[3]=Pierre
valeurs[0]=Lucette
valeurs[1]=
valeurs[2]=Virginie
valeurs[3]=Gisèle
La clé [Jacques] existe associée à la valeur [Lucette]
La clé [Lucette] n'existe pas
La clé [Jean] existe associée à la valeur []
Nombre d'éléments du dictionnaire : 3
conjoints[Jacques]=Lucette
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
Komentarze
Powyższy kod stosuje do słownika to, co omówiono wcześniej w przypadku zwykłej tablicy. Omówimy tylko nowe elementy:
- wiersz 12: funkcja ksort (sortowanie według klucza) pozwala posortować słownik w naturalnej kolejności kluczy;
- wiersz 19: funkcja array_keys($dictionnaire) zwraca listę kluczy słownika w postaci tablicy;
- wiersz 24: funkcja array_values($dictionnaire) zwraca listę wartości słownika w postaci tablicy;
- wiersz 43: funkcja isset($variable) zwraca TRUE, jeśli zmienna $variable została zdefiniowana, w przeciwnym razie zwraca FALSE;
- wiersz 33: funkcja unset($variable) usuwa zmienną $variable.
3.6.3. Tablice wielowymiarowe
Skrypt [bases-07.php] wygląda następująco:
<?php
// klasyczne tabele wielowymiarowe
// inicjalizacja
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// przeglądanie
for ($i1 = 0; $i1 < count($multi); $i1++) {
for ($i2 = 0; $i2 < count($multi[$i1]); $i2++) {
print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
}
}
// słowniki wielowymiarowe
// inicjalizacja
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// przeglądanie
foreach ($multi as $clé => $valeur) {
for ($i2 = 0; $i2 < count($valeur); $i2++) {
print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
}
}
Wyniki:
multi[0][0]=0
multi[0][1]=1
multi[0][2]=2
multi[1][0]=10
multi[1][1]=11
multi[1][2]=12
multi[1][3]=13
multi[2][0]=20
multi[2][1]=21
multi[2][2]=22
multi[2][3]=23
multi[2][4]=24
multi[zéro][0]=0
multi[zéro][1]=1
multi[zéro][2]=2
multi[un][0]=10
multi[un][1]=11
multi[un][2]=12
multi[un][3]=13
multi[deux][0]=20
multi[deux][1]=21
multi[deux][2]=22
multi[deux][3]=23
multi[deux][4]=24
Komentarze
- wiersz 5: elementy tablicy $multi same w sobie są tablicami;
- wiersz 14: tablica $multi staje się słownikiem (clé,valeur), w którym każda pozycja valeur jest tablicą;
3.7. Ciągi znaków
3.7.1. Notacja
Skrypt [bases-08.php] ma następującą postać:
<?php
// notacja ciągów znaków
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>
Wyniki:
3.7.2. Porównanie
Skrypt [bases-09.php] wygląda następująco:
<?php
// ścisłe przestrzeganie typów parametrów funkcji
declare(strict_types=1);
// funkcja porównywania
function compareModele2Chaine(string $chaine1, string $chaine2): void {
// porównuje ciąg1 i ciąg2
if ($chaine1 === $chaine2) {
print "[$chaine1] est égal à [$chaine2]\n";
} else {
print "[$chaine1] est différent de [$chaine2]\n";
}
}
// testy porównywania ciągów znaków
compareModele2Chaine("abcd", "abcd");
compareModele2Chaine("", "");
compareModele2Chaine("1", "");
exit;
Wyniki:
[abcd] est égal à [abcd]
[] est égal à []
[1] est différent de []
Uwagi
- wiersz 9 kodu: można było użyć operatora porównania == zamiast ===. Ten ostatni operator jest bardziej restrykcyjny, ponieważ wymaga, aby oba operandy były tego samego typu. Należy zauważyć, że w tym przypadku można go było zastąpić operatorem ==, ponieważ typ obu parametrów jest ustalony na string w sygnaturze funkcji;
3.7.3. Powiązania między ciągami znaków a tablicami
Skrypt [bases-10.php] wygląda następująco:
<?php
// przekształcanie ciągu znaków w tablicę
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// przeglądanie tablicy
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
}
// tablica do ciągu znaków
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// dodajmy puste pole
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// przeglądanie tablicy
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
} // mamy teraz 5 elementów, z których ostatni jest pusty
// dodajmy ponownie puste pole
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// przeglądanie tablicy
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
} // mamy teraz 6 elementów, z których dwa ostatnie są puste
Wyniki:
tab a 4 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
chaine2=1:2:3:4
chaîne=1:2:3:4:
tab a 5 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
chaîne=1:2:3:4::
tab a 6 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
tab[5]=
Komentarze
- wiersz 5: funkcja explode($séparateur,$chaine) pozwala pobrać pola z pliku $chaine, oddzielone przez $séparateur. W ten sposób funkcja explode(":",$chaine) pozwala pobrać w postaci tablicy elementy z $chaine, które są oddzielone ciągiem znaków „:”;
- wiersz 12: funkcja implode($séparateur,$tableau) wykonuje operację odwrotną do funkcji explode. Zwraca ciąg znaków utworzony z elementów $tableau oddzielonych przez $séparateur;
3.7.4. Wyrażenia regularne
Skrypt [bases-11.php] wygląda następująco:
<?php
// ścisły typ dla parametrów funkcji
declare (strict_types=1);
// wyrażenia regularne w PHP
// pobieranie poszczególnych pól z ciągu znaków
// wzór: ciąg cyfr otoczony dowolnymi znakami
// chcemy pobrać tylko ciąg cyfr
$modèle = "/(\d+)/";
// porównujemy ciąg znaków z wzorcem
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");
// wzór: ciąg cyfr otoczony dowolnymi znakami
// chcemy uzyskać ciąg cyfr wraz z polami poprzedzającymi i następującymi po nim
$modèle = "/^(.*?)(\d+)(.*?)$/";
// porównujemy ciąg znaków z wzorcem
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");
// wzorzec – data w formacie dd/mm/rr
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
compareModele2Chaine($modèle, "10/05/97");
compareModele2Chaine($modèle, " 04/04/01 ");
compareModele2Chaine($modèle, "5/1/01");
// wzór – liczba dziesiętna
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
compareModele2Chaine($modèle, "187.8");
compareModele2Chaine($modèle, "-0.6");
compareModele2Chaine($modèle, "4");
compareModele2Chaine($modèle, ".6");
compareModele2Chaine($modèle, "4.");
compareModele2Chaine($modèle, " + 4");
// koniec
exit;
// --------------------------------------------------------------------------
function compareModele2Chaine(string $modèle, string $chaîne): void {
// porównuje ciąg znaków $chaîne z wzorcem $modèle
// porównuje się ciąg znaków z wzorcem
$champs = [];
$correspond = preg_match($modèle, $chaîne, $champs);
// wyświetlanie wyników
print "\nRésultats($modèle,$chaîne)\n";
if ($correspond) {
for ($i = 0; $i < count($champs); $i++) {
print "champs[$i]=$champs[$i]\n";
}
} else {
print "La chaîne [$chaîne] ne correspond pas au modèle [$modèle]\n";
}
}
Wyniki:
Résultats(/(\d+)/,xyz1234abcd)
champs[0]=1234
champs[1]=1234
Résultats(/(\d+)/,12 34)
champs[0]=12
champs[1]=12
Résultats(/(\d+)/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/(\d+)/]
Résultats(/^(.*?)(\d+)(.*?)$/,xyz1234abcd)
champs[0]=xyz1234abcd
champs[1]=xyz
champs[2]=1234
champs[3]=abcd
Résultats(/^(.*?)(\d+)(.*?)$/,12 34)
champs[0]=12 34
champs[1]=
champs[2]=12
champs[3]= 34
Résultats(/^(.*?)(\d+)(.*?)$/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/^(.*?)(\d+)(.*?)$/]
Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,10/05/97)
champs[0]=10/05/97
champs[1]=10
champs[2]=05
champs[3]=97
Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/, 04/04/01 )
champs[0]= 04/04/01
champs[1]=04
champs[2]=04
champs[3]=01
Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,5/1/01)
La chaîne [5/1/01] ne correspond pas au modèle [/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/]
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,187.8)
champs[0]=187.8
champs[1]=
champs[2]=187.8
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,-0.6)
champs[0]=-0.6
champs[1]=-
champs[2]=0.6
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4)
champs[0]=4
champs[1]=
champs[2]=4
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,.6)
champs[0]=.6
champs[1]=
champs[2]=.6
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4.)
champs[0]=4.
champs[1]=
champs[2]=4.
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/, + 4)
champs[0]= + 4
champs[1]=+
champs[2]=4
Komentarze
- W tym przypadku wykorzystujemy wyrażenia regularne do wyodrębnienia różnych pól z ciągu znaków. Wyrażenia regularne pozwalają obejść ograniczenia funkcji implode. Zasadą działania jest porównanie ciągu znaków z innym ciągiem o nazwie modèle za pomocą funkcji preg_match:
$correspond = preg_match($modèle, $chaîne, $champs);
Funkcja preg_match zwraca wartość logiczną TRUE, jeśli ciąg modèle występuje w ciągu chaîne. Jeśli tak, to $champs[0] reprezentuje podciąg odpowiadający szablonowi. Ponadto, jeśli modèle zawiera podmodele w nawiasach, to $champs[1] jest fragmentem $chaîne odpowiadającym pierwszemu podmodelowi, $champs[2] to fragment ciągu $chaîne odpowiadający drugiemu podwzorowi itd.
Rozważmy pierwszy przykład. Wzorzec jest zdefiniowany w wierszu 10: oznacza on ciąg jednej lub więcej (+) cyfr (\d) umieszczonych w dowolnym miejscu ciągu znaków. Ponadto wzorzec definiuje podwzorzec ujęty w nawiasy;
- wiersz 12: wzorzec /(\d+)/ (sekwencja jednej lub więcej cyfr w dowolnym miejscu ciągu) jest porównywany z ciągiem „xyz1234abcd”. Widać, że podciąg 1234 odpowiada wzorcowi. W związku z tym $champs[0] będzie równe „1234”. Ponadto wzorzec zawiera podwzorce w nawiasach. Otrzymamy $champs[1] = „1234”;
- wiersz 13: wzorzec /(\d+)/ jest porównywany z ciągiem znaków „12 34”. Widzimy, że podciągi 12 i 34 odpowiadają wzorcowi. Porównanie kończy się przy pierwszym podciągu odpowiadającym wzorcowi. Otrzymamy zatem: $champs[0]=12 oraz $champs[1]=12;
- wiersz 14: wzorzec /(\d+)/ jest porównywany z ciągiem „abcd”. Nie znaleziono żadnego dopasowania;
Wyjaśnijmy wzorce użyte w dalszej części kodu:
$modèle = "/^(.*?)(\d+)(.*?)$/";
odpowiada początkowi ciągu znaków (^), następnie 0 lub więcej (*) dowolnych znaków (.), następnie 1 lub więcej (+) cyfr, a następnie ponownie 0 lub więcej (*) dowolnych znaków (.). Wzorzec (.*) oznacza 0 lub więcej dowolnych znaków. Taki wzorzec będzie pasował do dowolnego ciągu znaków. W związku z tym wzorzec /^(.*)(\d+)(.*)$/ nigdy nie zostanie znaleziony, ponieważ pierwszy podwzorzec (.*) pochłonie cały ciąg znaków. Wzorzec (.*?)(\d+) oznacza natomiast 0 lub więcej dowolnych znaków aż do następnego podwzorca (?), w tym przypadku \d+. Zatem cyfry nie są już pochłaniane przez wzorzec (.*). Powyższy wzorzec pasuje zatem do ciągu [début de chaîne (^), une suite de caractères quelconques (.*?), une suite d'un ou plusieurs chiffres (\d+), une suite de caractères quelconques (.*?), la fin de la chaîne ($)].
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
odpowiada [début de chaîne (^), 2 chiffres (\d\d), le caractère / (\/), 2 chiffres, /, 2 chiffres, une suite de 0 ou plusieurs espaces (\s*), la fin de chaîne ($)].
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
odpowiada początkowi ciągu (^), 0 lub więcej spacji (\s*), znakowi + lub - [+|-] występującemu 0 lub 1 raz (?), sekwencji 0 lub więcej spacji (\s*), 1 lub więcej cyfr, po których następuje kropka dziesiętna, a po niej zero lub więcej cyfr (\d+\.\d*) lub (|) kropka dziesiętna (\.) po której następuje jedna lub więcej cyfr (\d+) lub (|) jedna lub więcej cyfr (\d+), sekwencja 0 lub więcej spacji (\s*)].
Uwaga: termin [espace] w wyrażeniach regularnych oznacza zbiór znaków: spacja, znak końca linii \n, tabulator \t, znak powrotu karetki \r, znak końca strony \f…
3.8. Funkcje
3.8.1. Sposób przekazywania parametrów
Skrypt [base-12.php] wygląda następująco:
<?php
// sposób przekazywania parametrów funkcji
// ścisłe przestrzeganie typu parametrów
declare(strict_types=1);
function f(int &$i, int $j): void {
// $i zostanie przekazany przez odwołanie
// $j zostanie przekazane jako wartość
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
// testy
$i = 0;
$j = 0;
// $i i $j są przekazywane do funkcji f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
Wyniki:
Komentarze
Powyższy kod ilustruje dwa sposoby przekazywania parametrów do funkcji. Rozważmy następujący przykład:
- wiersz 1: definiuje parametry formalne $a i $b funkcji f. Funkcja ta przetwarza te dwa parametry formalne i zwraca wynik;
- wiersz 7: wywołanie funkcji f z dwoma parametrami rzeczywistymi $i i $j. Powiązania między parametrami formalnymi ($a, $b) a parametrami rzeczywistymi ($i, $j) są zdefiniowane w wierszach 1 i 7:
- &$a: znak & oznacza, że parametr formalny $a przyjmie jako wartość adres parametru rzeczywistego $i. Innymi słowy, $a i $i to dwa odwołania do tej samej lokalizacji w pamięci. Manipulowanie parametrem formalnym $a jest równoznaczne z manipulowaniem parametrem rzeczywistym $i. Pokazuje to wykonanie kodu. Ten sposób przekazywania nadaje się do parametrów wyjściowych oraz dużych zbiorów danych, takich jak tablice i słowniki. Ten sposób przekazywania nazywa się przekazywaniem przez odwołanie.
- $b: parametr formalny $b przyjmie wartość parametru rzeczywistego $j. Jest to przekazywanie przez wartość. Parametry formalne i rzeczywiste to dwie różne zmienne. Manipulowanie parametrem formalnym $b nie ma żadnego wpływu na parametr rzeczywisty $j. Pokazuje to wykonanie kodu. Ten tryb przekazywania nadaje się do parametrów wejściowych.
- Weźmy na przykład funkcję échange, która przyjmuje dwa parametry formalne: $a i $b. Funkcja ta zamienia wartości tych dwóch parametrów. Zatem podczas wywołania typu „zamiana” ($i,$j) kod wywołujący oczekuje, że wartości obu parametrów rzeczywistych zostaną zamienione. Są to zatem parametry wyjściowe (ulegają one modyfikacji). Napiszemy zatem:
Poniższy skrypt [base-13.php] przedstawia inne przykłady:
<?php
// typy w trybie ścisłym
// declare(strict_types = 1);
// sposób przekazywania parametrów
function f(&$i, $j) {
// $i będzie przekazywany przez odwołanie
// $j zostanie przekazane jako wartość
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
function g(int &$i, int $j) : void {
// $i zostanie pobrany przez odwołanie
// $j zostanie uzyskany przez wartość
$i++;
$j++;
print "g[i,j]=[$i,$j]\n";
}
// testy
$i = 0;
$j = 0;
// $i i $j zostały przekazane do funkcji f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
// $i i $j są przekazywane do funkcji g
g($i, $j);
print "test[i,j]=[$i,$j]\n";
// do funkcji f przekazano nieprawidłowe parametry
$a=5.3;
$b=6.2;
f($a, $b);
print "test[a,b]=[$a,$b]\n";
// do funkcji f przekazywane są nieprawidłowe parametry
$a=5.3;
$b=6.2;
g($a, $b);
print "test[a,b]=[$a,$b]\n";
Komentarze
- wiersze 8–14: funkcja f omówiona w poprzednim akapicie, ale nie określono typów parametrów;
- wiersze 16–22: funkcja g działa tak samo jak funkcja f, ale podano typy oczekiwanych parametrów – to nowość PHP 7. Oczekuje się dwóch parametrów typu int. Chcemy sprawdzić, co się stanie, gdy rzeczywisty parametr przekazany do funkcji nie ma typu oczekiwanego przez tę funkcję;
- wiersze 25–26: $i i $j to dwie liczby całkowite;
- wiersze 28–29: wywołanie funkcji f z parametrami o oczekiwanym typie;
- wiersze 31–32: wywołanie funkcji g z parametrami o oczekiwanym typie;
- wiersze 34–35: zmienne $a i $b są typu float;
- wiersze 36–37: wywołanie funkcji f z parametrami, które nie są typu oczekiwanego;
- wiersze 41–42: wywołanie funkcji g z parametrami, które nie są typu oczekiwanego;
Wyniki
- wiersze 5–6 pokazują, że funkcja f przyjęła oba parametry typu float i wykonała na nich operacje;
- wiersze 7–8 pokazują, że funkcja g przyjęła oba parametry typu float, ale przekształciła je na typ int (wiersz 7);
Teraz usuńmy komentarz z wiersza 4:
Ta instrukcja wskazuje, że typy parametrów formalnych muszą być zachowane. Jeśli tak nie jest, zgłaszany jest błąd. Wyniki wykonania wyglądają wówczas następująco:
- wiersze 9–10: interpreter PHP 7 zgłosił wyjątek, wskazując, że pierwszy parametr przekazany do funkcji g miał nieprawidłowy typ. Zaleca się rygorystyczne przestrzeganie typów parametrów, ilekroć jest to możliwe, w celu wykrywania błędów wywoływania funkcji;
3.8.2. Wyniki zwracane przez funkcję
Skrypt [base-15.php] wygląda następująco:
<?php
// typy w trybie ścisłym
declare(strict_types=1);
// wyniki zwracane przez funkcję
// funkcja może zwracać wiele wartości w tablicy
list($res1, $res2, $res3) = f1(10);
print "[$res1,$res2,$res3]\n";
$res = f1(10);
for ($i = 0; $i < count($res); $i++) {
print "f1 : res[$i]=$res[$i]\n";
}
// funkcja może zwracać obiekt
$res = f2(10);
print "f2 : [$res->res1,$res->res2,$res->res3]\n";
// obiekt jakiego rodzaju?
print "nature de l'objet : ";
var_dump($res);
print "\n";
// to samo robimy z funkcją f3
$res = f3(10);
print "f3 : [$res->res1,$res->res2,$res->res3]\n";
// jakiego rodzaju obiekt?
print "nature de l'objet : ";
var_dump($res);
print "\n";
// koniec
exit;
// funkcja f1
function f1(int $valeur): array {
// zwraca tablicę ($valeur+1,$valeur+2,$valeur+3)
return array($valeur + 1, $valeur + 2, $valeur + 3);
}
// funkcja f2
function f2(int $valeur): object {
// zwraca obiekt ($valeur+1,$valeur+2,$valeur+3)
$res->res1 = $valeur + 1;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// zwraca obiekt
return $res;
}
// funkcja f3 – działa tak samo jak funkcja f2
function f3(int $valeur): object {
// zwraca obiekt ($valeur+1,$valeur+2,$valeur+3)
$res = new stdclass();
$res->res1 = $valeur + 1;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// zwraca obiekt
return $res;
}
Wyniki
[11,12,13]
f1 : res[0]=11
f1 : res[1]=12
f1 : res[2]=13
Warning: Creating default object from empty value in C:\Data\st-2019\dev\php7\php5-exemples\exemples\bases\base-15.php on line 43
f2 : [11,12,13]
nature de l'objet : object(stdClass)#1 (3) {
["res1"]=>
int(11)
["res2"]=>
int(12)
["res3"]=>
int(13)
}
f3 : [11,12,13]
nature de l'objet : object(stdClass)#2 (3) {
["res1"]=>
int(11)
["res2"]=>
int(12)
["res3"]=>
int(13)
}
Komentarze
- poprzedni program pokazuje, że funkcja PHP może zwracać zbiór wyników, a nie tylko jeden, w postaci tablicy lub obiektu. Pojęcie obiektu zostanie wyjaśnione nieco dalej;
- wiersze 35–38: funkcja f1 zwraca wiele wartości w postaci tablicy (array);
- wiersze 41–48: funkcja f2 zwraca wiele wartości w postaci obiektu (object);
- wiersze 51–59: funkcja f3 jest identyczna z funkcją f2, z tą różnicą, że w wierszu 53 jawnie tworzy obiekt;
- w wierszu 6 wyników pojawia się ostrzeżenie (warning) wskazujące, że funkcja PHP została zmuszona do utworzenia obiektu domyślnego w wierszu 43 kodu, tj. podczas użycia notacji [$res→res1]. Funkcja var_dump w wierszu 20 kodu umożliwia sprawdzenie typu obiektu i jego zawartości. W wynikach widać, że:
- wiersz 8: obiekt utworzony domyślnie jest typu stdClass;
- wiersze 9–10: właściwość res1 jest typu entier i ma wartość 11;
- itd…
- aby uniknąć ostrzeżenia z wiersza 6 wyników, w wierszu 53 funkcji f3 tworzymy jawnie obiekt typu stdClass;
3.9. Pliki tekstowe
Skrypt [bases-16.php] wygląda następująco:
<?php
// ścisłe przestrzeganie typów parametrów funkcji
declare (strict_types=1);
// sekwencyjne przetwarzanie pliku tekstowego
// plik ten stanowi zbiór wierszy o postaci login:pwd:uid:gid:infos:dir:shell
// każdy wiersz jest umieszczany w słowniku w postaci login => uid:gid:infos:dir:shell
// ustalamy nazwę pliku
$INFOS = "infos.txt";
// otwieramy go w trybie tworzenia
if (!$fic = fopen($INFOS, "w")) {
print "Erreur d'ouverture du fichier $INFOS en écriture\n";
exit;
}
// generuje się dowolną treść
for ($i = 0; $i < 100; $i++) {
fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
}
// zamykamy plik
fclose($fic);
// wykorzystujemy to – funkcja fgets zachowuje znacznik końca linii
// dzięki temu podczas odczytu pustej linii nie pobierany jest pusty ciąg znaków
// otwieramy go do odczytu
if (!$fic = fopen($INFOS, "r")) {
print "Erreur d'ouverture du fichier $INFOS en lecture\n";
exit;
}
// wiersze mają mniej niż 1000 znaków
// odczyt wiersza kończy się na znaku końca wiersza
// lub znaku końca pliku
while ($ligne = fgets($fic, 1000)) {
// usuwamy znak końca linii, jeśli istnieje
$ligne = cutNewLineChar($ligne);
// umieszczamy wiersz w tabeli
$infos = explode(":", $ligne);
// pobieramy login
$login = array_shift($infos);
// pomijamy hasło
array_shift($infos);
// tworzymy wpis w słowniku
$dico[$login] = $infos;
}
// zamykamy go
fclose($fic);
// wykorzystanie słownika
afficheInfos($dico, "login10");
afficheInfos($dico, "X");
// koniec
exit;
// --------------------------------------------------------------------------
function afficheInfos(array $dico, string $clé): void {
// wyświetla wartość powiązaną z kluczem w słowniku $dico, jeśli istnieje
if (isset($dico[$clé])) {
// wartość istnieje – czy jest to tablica?
$valeur = $dico[$clé];
if (is_array($valeur)) {
print "[$clé," . join(":", $valeur) . "]\n";
} else {
// $valeur nie jest tablicą
print "[$clé,$valeur]\n";
}
} else {
// $clé nie jest kluczem słownika $dico
print "la clé [$clé] n'existe pas\n";
}
}
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
// usuwamy znacznik końca linii z $ligne, jeśli istnieje
$L = strlen($ligne); // długość wiersza
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// koniec
return($ligne);
}
Plik infos.txt:
Wyniki:
[login10,uid10:gid10:infos10:dir10:shell10]
la clé [X] n'existe pas
Komentarze
- wiersz 12: fopen(nom_fichier, „w”) otwiera plik nom_fichier w trybie zapisu (w=write). Jeśli plik nie istnieje, zostanie utworzony. Jeśli istnieje, zostanie wyczyszczony. Jeśli utworzenie pliku nie powiedzie się, fopen zwraca wartość false. W instrukcji if (!$fic = fopen($INFOS, "w")) {…} występują dwie kolejne operacje: 1) $fic = fopen(..) 2) if( ! $fic) {…};
- wiersz 18: fputs($fic,$chaîne) zapisuje chaîne do pliku $fic. Plik $chaine jest zapisywany z znakiem końca linii \n na końcu;
- wiersz 21: fclose($fic) zamyka plik $fic;
- wiersz 26: fopen(nom_fichier, „r”) otwiera plik nom_fichier w trybie odczytu (r=read). Jeśli otwarcie się nie powiedzie (na przykład plik nie istnieje), fopen zwraca wartość false;
- wiersz 34: fgets($fic, 1000) odczytuje następny wiersz z pliku, ograniczając długość do 1000 znaków. W pętli while ($ligne = fgets($fic, 1000)) {…} występują dwie kolejne operacje: 1) $ligne = fgets(…) 2) while ( ! $ligne). Po odczytaniu ostatniego znaku z pliku funkcja fgets zwraca wartość false, a pętla while zostaje zatrzymana. Funkcja fgets próbuje tutaj odczytać maksymalnie 1000 znaków, ale zatrzymuje się natychmiast po napotkaniu znaku końca linii. Ponieważ wszystkie linie mają mniej niż 1000 znaków, funkcja [fgets] odczytuje jedną linię tekstu, łącznie ze znakiem końca linii. Funkcja cutNewLineChar w wierszach 75–84 usuwa ewentualne znaki końca linii;
- wiersz 77: funkcja strlen($chaîne) zwraca liczbę znaków w $chaîne;
- wiersz 78: funkcja substr($ligne, $position, $taille) zwraca $taille znaków z ciągu $ligne, począwszy od znaku o numerze $position, przy czym pierwszy znak ma numer 0. Na komputerach z systemem Windows znakiem końca linii jest „\r\n”. Na komputerach z systemem Unix jest to ciąg znaków „\n”;
- wiersz 40: funkcja array_shift($tableau) usuwa pierwszy element z $tableau i zwraca go jako wynik. Pomija się tutaj wynik zwracany przez array_shift;
- wiersz 62: funkcja is_array($variable) zwraca true, jeśli $variable jest tablicą, w przeciwnym razie zwraca false;
- wiersz 63: funkcja join działa tak samo jak omówiona wcześniej funkcja implode;
3.10. Kodowanie / dekodowanie jSON

Kodowanie / dekodowanie jSON (JavaScript Object Notation) jest czymś, z czego będziemy intensywnie korzystać w ćwiczeniu stanowiącym motyw przewodni niniejszego dokumentu. Skrypty [json-01.php, json-02.php, json-03.php] wyjaśniają, co należy wiedzieć przed przystąpieniem do dalszych czynności.
Skrypt [json-01.php] ma następującą postać:
<?php
$array1 = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34];
// kodowanie JSON tablicy array1 z znakami Unicode z symbolami escape
print "encodage json du tableau array1 avec caractères Unicode échappés\n";
$json1 = json_encode($array1);
print "json1=$json1\n";
// kodowanie JSON tablicy array1 z nieeskapowanymi znakami Unicode
print "encodage json du tableau array1 avec caractères Unicode non échappés\n";
$json2 = json_encode($array1, JSON_UNESCAPED_UNICODE);
print "json2=$json2\n";
// dekodowanie jSON do tablicy asocjacyjnej
print "décodage jSON de json2 dans tableau associatif\n";
$array2 = json_decode($json2, true);
var_dump($array2);
foreach ($array2 as $key => $value) {
print "$key:$value\n";
}
// dekodowanie jSON do obiektu
print "décodage jSON de json2 dans objet stdClass\n";
$array2 = json_decode($json2);
var_dump($array2);
print "prénom=$array2->prénom\n";
print "nom=$array2->nom\n";
print "âge=$array2->âge\n";
Wyniki
Komentarze
- wiersz 6 kodu: funkcja [json_encode] przekształca swój parametr w ciąg znaków jSON;
- wiersz 2 wyników: wygenerowany ciąg znaków jSON. Znaki Unicode „éâ” zostały zastąpione ich kodami Unicode zaczynającymi się od \u;
- wiersz 10 kodu: powtarzamy tę samą operację, tym razem z żądaniem, aby znaki Unicode zostały zachowane bez zmian;
- wiersz 4 wyników: wynikowy ciąg znaków jSON. Jest on znacznie bardziej czytelny;
- wiersze 14–18 kodu: wykonujemy operację odwrotną. Przekształcamy ciąg znaków jSON w tablicę asocjacyjną;
- wiersze 6–13 wyników: widać, że uzyskano tablicę asocjacyjną;
- wiersze 19–25 kodu: przekształcamy ciąg znaków jSON w obiekt typu [stdClass];
- wiersze 18–25 wyników: widać, że uzyskano obiekt typu [stdClass];
- wiersze 23–25 kodu: atrybut A obiektu O ma wartość [O→A];
W formacie jSON można kodować tabele wielopoziomowe, jak pokazuje poniższy skrypt [json-02.php]:
<?php
$array = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34,
"mari" => ["nom" => "icariù", "prénom" => "ignacio", "âge" => 35],
"enfants" => [
["prénom" => "angèle", "age" => 8],
["prénom" => "andré", "age" => 2],
]];
// kodowanie jSON tablicy wielopoziomowej
print "encodage jSON d'un tableau à plusieurs niveaux\n";
$json = json_encode($array, JSON_UNESCAPED_UNICODE);
print "json=$json\n";
Wyniki
encodage jSON d'un tableau à plusieurs niveaux
json={"nom":"séléné","prénom":"bénédicte","âge":34,"mari":{"nom":"icariù","prénom":"ignacio","âge":35},"enfants":[{"prénom":"angèle","age":8},{"prénom":"andré","age":2}]}
Komentarze
W ciągu znaków jSON:
- tabele nieasocjacyjne są ujęte w nawiasy kwadratowe [];
- tabele asocjacyjne są ujęte w nawiasy klamrowe {};
Skrypt [json-03.php] pokazuje, jak wykorzystać następujący plik jSON [famille.json]:
{
"épouse": {
"nom": "séléné",
"prénom": "bénédicte",
"âge": 34
},
"mari": {
"nom": "icariù",
"prénom": "ignacio",
"âge": 35
},
"enfants": [
{
"prénom": "angèle",
"age": 8
},
{
"prénom": "andré",
"age": 2
}
]
}
Skrypt [json-03.php] ma następującą postać:
<?php
// odczyt pliku jSON
$json = file_get_contents("famille.json");
// dekodowanie JSON do obiektu
$famille1 = json_decode($json);
print "----famille1\n";
var_dump($famille1);
// dekodowanie JSON do tablicy asocjacyjnej
print "----famille2\n";
$famille2 = json_decode($json, true);
var_dump($famille2);
Komentarze
- wiersz 4: funkcja [file_get_contents] odczytuje zawartość pliku o nazwie [famille.json] i umieszcza ją w zmiennej [$json];
- następnie zmienna jest dekodowana do obiektu (wiersze 5–8) i tablicy asocjacyjnej (wiersze 9–12);
Wyniki
----famille1
object(stdClass)#2 (3) {
["épouse"]=>
object(stdClass)#1 (3) {
["nom"]=>
string(9) "séléné"
["prénom"]=>
string(11) "bénédicte"
["âge"]=>
int(34)
}
["mari"]=>
object(stdClass)#3 (3) {
["nom"]=>
string(7) "icariù"
["prénom"]=>
string(7) "ignacio"
["âge"]=>
int(35)
}
["enfants"]=>
array(2) {
[0]=>
object(stdClass)#4 (2) {
["prénom"]=>
string(7) "angèle"
["age"]=>
int(8)
}
[1]=>
object(stdClass)#5 (2) {
["prénom"]=>
string(6) "andré"
["age"]=>
int(2)
}
}
}
----famille2
array(3) {
["épouse"]=>
array(3) {
["nom"]=>
string(9) "séléné"
["prénom"]=>
string(11) "bénédicte"
["âge"]=>
int(34)
}
["mari"]=>
array(3) {
["nom"]=>
string(7) "icariù"
["prénom"]=>
string(7) "ignacio"
["âge"]=>
int(35)
}
["enfants"]=>
array(2) {
[0]=>
array(2) {
["prénom"]=>
string(7) "angèle"
["age"]=>
int(8)
}
[1]=>
array(2) {
["prénom"]=>
string(6) "andré"
["age"]=>
int(2)
}
}
}
Komentarze
- wiersze 1–38: obiekt powstały w wyniku dekodowania pliku jSON [famille.json];
- wiersze 39–76: tablica asocjacyjna uzyskana w wyniku dekodowania pliku jSON [famille.json];