3. Основи PHP
3.1. Структура скриптів

3.2. Налаштування PHP
PHP постачається з попередньо налаштованим текстовим файлом [php.ini]. Усі ці налаштування можна змінити програмно. Налаштування PHP суттєво впливає на виконання скриптів. Тому важливо знати про нього. Це можна зробити за допомогою наступного скрипта [phpinfo.php]:
Коментарі
- рядок 3: функція [phpinfo] виводить конфігурацію PHP;
Результати виконання
Функція [phpinfo] відображає тут понад 800 рядків конфігурації. Ми не будемо їх коментувати, оскільки більшість із них стосується розширеного використання PHP. Важливим є рядок 13 вище: він вказує, який файл [php.ini] було використано для налаштування PHP, який ви будете використовувати для виконання своїх скриптів. Якщо ви хочете змінити налаштування виконання PHP, саме цей файл вам потрібно редагувати. У цьому файлі міститься багато коментарів, що пояснюють роль різних налаштувань.
3.3. Перший приклад
3.3.1. Код
Нижче наведено програму [bases-01.php], яка демонструє основні можливості PHP.
<?php
// це коментар
// змінна, що використовується без оголошення
$nom = "dupont";
// виведення на екран
print "nom=$nom\n";
// масив з елементами різних типів
$tableau = array("un", "deux", 3, 4);
// кількість елементів
$n = count($tableau);
// цикл
for ($i = 0; $i < $n; $i++) {
print "tableau[$i]=$tableau[$i]\n";
}
// ініціалізація 2 змінних вмістом масиву
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// об'єднання двох рядків
$chaine3 = $chaine1 . $chaine2;
// виведення результату
print "[$chaine1,$chaine2,$chaine3]\n";
// використання функції
affiche($chaine1);
// тип змінної може бути відомим
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// тип змінної може змінюватися під час виконання
$n = "a changé";
afficheType("n", $n);
// функція може повертати результат
$res1 = f1(4);
print "res1=$res1\n";
// функція може повертати масив значень
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// ці значення можна було б зберегти у масиві
$t = f2();
for ($i = 0; $i < count($t); $i++) {
print "t[$i]=$t[$i]\n";
}
// тести
for ($i = 0; $i < count($t); $i++) {
// виводить лише рядки
if (getType($t[$i]) === "string") {
print "t[$i]=$t[$i]\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";
}
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";
}
// інші тести
for ($i = 0; $i < count($t); $i++) {
// виводить лише цілі числа >10
if (getType($t[$i]) === "integer" and $t[$i] > 10) {
print "t[$i]=$t[$i]\n";
}
}
// цикл 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";
// кінець програми
exit;
//----------------------------------
function affiche($chaine) {
// виводить $chaine
print "chaine=$chaine\n";
}
//виводить
//----------------------------------
function afficheType($name, $variable) {
// виводить тип $variable
print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}
//afficheType
//----------------------------------
function f1($param) {
// додає 10 до $param
return $param + 10;
}
//----------------------------------
function f2() {
// повертає 3 значення
return array("un", 0, 100);
}
?>
Результати:
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
Коментарі
- рядок 5: у програмі PHP тип змінних не оголошується. Вони мають динамічний тип, який може змінюватися з часом. $nom позначає змінну з ідентифікатором nom;
- рядок 7: для виведення на екран можна використовувати оператор print або оператор echo;
- рядок 9: ключове слово array дозволяє визначити масив. Змінна $nom[$i] представляє елемент $i масиву $tableau;
- рядок 11: функція count($tableau) повертає кількість елементів масиву $tableau;
- рядки 13–15: цикл. Оскільки він містить лише одну інструкцію, фігурні дужки є необов’язковими. У подальшому тексті цього документа ми будемо систематично вказувати фігурні дужки незалежно від кількості інструкцій;
- рядок 14: символьні рядки беруться в лапки " або апострофи '. Усередині лапок змінні $variable обчислюються, але не всередині апострофів;
- рядок 17: функція list дозволяє об’єднати змінні у список і присвоїти їм значення за допомогою однієї операції присвоєння. Тут $chaine1="chaine1" та $chaine2="chaine2";
- рядок 19: оператор . — це оператор конкатенації рядків;
- рядки 83–86: ключове слово function визначає функцію. Функція може повертати значення або не повертати їх за допомогою оператора return. Код, що викликає функцію, може ігнорувати або отримувати результати функції. Функцію можна визначити в будь-якому місці коду.
- рядок 92: попередньо визначена функція getType($variable) повертає рядок символів, що представляє тип $variable. Цей тип може змінюватися з часом;
- рядок 45: оператор === порівнює два елементи строго: для порівняння вони повинні мати однаковий тип. Оператор == є менш суворим: два елементи можуть бути рівними, не маючи однакового типу. Це ілюструють інструкції в рядках 50–60. У випадку оператора == порівняння відбувається після приведення типів обох порівнюваних елементів до одного типу. При цьому відбуваються неявні перетворення. Досить легко «забути» про наявність цих неявних перетворень і, таким чином, отримати непередбачувані результати, наприклад, виявити, що умова є істинною, хоча ви очікували, що вона буде хибною. Щоб уникнути цієї пастки, ми будемо систематично використовувати оператор порівняння ===;
- рядок 64: також можна використовувати булеві оператори or та !;
- рядок 69: замість запису array() можна використовувати запис [] для ініціалізації масиву з PHP7;
- рядок 80: вбудована функція exit зупиняє виконання скрипта;
- рядок 107: тег ?> позначає кінець скрипта PHP. Він не є обов’язковим. Крім того, у веб-контексті вона може спричинити проблеми, якщо за нею йдуть пробіли або символи кінця рядка, які важко виявити, оскільки вони невидимі в текстовому редакторі. Тому в подальшому тексті ми будемо систематично опускати цей тег;
Примітка: у цьому документі ми будемо використовувати ключове слово [print] для виведення тексту на консоль. Інший спосіб зробити те саме — використати ключове слово [echo]. Між цими двома ключовими словами є незначні відмінності, але в контексті цього документа вони не матимуть значення. Тож якщо ви вважаєте за краще використовувати [echo], то робіть це.
3.3.2. Використання NetBeans
NetBeans видає різні попередження, на які варто звернути увагу. Розглянемо приклад скрипта [bases-01.php]:

У рядку 5 NetBeans видає попередження про те, що файл не відповідає рекомендації PSR-1 (PHP, Стандартні рекомендації № 1). PSR — це рекомендації щодо створення стандартного коду, що полегшують взаємодію та обслуговування коду, написаного різними людьми. Отримання попереджень може бути неприємним, якщо ви навмисно хочете порушити стандарти, наприклад, тому що команда проєкту дотримується інших стандартів. Те, що ви хочете перевіряти або не перевіряти за допомогою NetBeans, можна налаштувати:

- у [5] містяться елементи, які ми хочемо перевіряти за допомогою NetBeans;
- у [6] — рівень серйозності, присвоєний помилці, про яку повідомляє NetBeans;

У [7] видно, що було задано перевірку на відповідність коду рекомендаціям PSR-0 та PSR-1. Нічого обов’язкового тут немає. На етапі вивчення мови рекомендується перевіряти якомога більше опцій, які пропонує NetBeans. Так можна багато чого навчитися. Згодом цю перевірку NetBeans буде адаптовано до стандартів кодування команди проекту.
Розглянемо стандарти кодування PSR-1 та [8, 9]:
Параметр | Перевірка |
| Константи класу MUST повинні оголошуватися великими літерами з розділювачами у вигляді підкреслення. Наприклад: const TAUX_TVA |
| Імена методів MUST слід оголошувати в camelCase(). Приклад: public function executeBatchImpots{} |
| Імена властивостей SHOULD мають бути оголошені у форматі $StudlyCaps, $camelCase або $under_score (послідовно в одній області видимості) Наприклад: public SalaireAnnuel (StudlyCaps), public salaireAnnuel (camelCase), public salaire_annuel (under_score) |
| Файл SHOULD оголошує нові символи і не спричиняє інших побічних ефектів, або він SHOULD виконує логіку з побічними ефектами, але SHOULD NOT робить і те, і інше. |
| Імена типів MUST повинні бути оголошені в StudlyCaps (Код, написаний для версій 5.2.x та раніше SHOULD, використовує конвенцію псевдопростору імен із префіксами Vendor_ у назвах типів). Кожен тип міститься в окремому файлі та належить до простору імен щонайменше одного рівня: імені постачальника найвищого рівня. Наприклад: class EtudiantBoursier {} |
Рекомендація PSR-1 / 4 передбачає, що у файлі PHP має міститися:
- або оголошення типу (класів, інтерфейсів);
- або виконуваний код без оголошення нових типів;
Існують також інші рекомендації PHP, які не перевіряються NetBeans: PSR-3, PSR-4, PSR-6, PSR-7 та PSR-13.
Для зручності не всі приклади в цьому документі відповідають рекомендації PSR-1, оскільки це вимагає розміщення коду класів та інтерфейсів у окремих файлах, що є занадто обтяжливим для базових прикладів. Тому простіше розмістити все в одному файлі. У прикладі додатка, який є провідною темою цього документа, ми намагалися максимально дотримуватися рекомендації PSR-1.
Деякі попередження NetBeans вказують на потенційну помилку:

Попередження [Unitialized Variables] вказує на ймовірну помилку, найчастіше — на помилку в написанні імені змінної. Те саме стосується попередження [Unused Variables].
Нарешті, рекомендується перевірити всі попередження NetBeans, що позначаються панеллю у лівому полі коду та жовтою рискою у правому полі:


3.4. Область дії змінних
3.4.1. Приклад 1
Скрипт [bases-02.php] має такий вигляд:
<?php
// область дії змінних
function f1() {
// використовується глобальна змінна $i
global $i;
$i++;
$j = 10;
print "f1[i,j]=[$i,$j]\n";
}
function f2() {
// використовується глобальна змінна $i
global $i;
$i++;
$j = 20;
print "f2[i,j]=[$i,$j]\n";
}
function f3() {
// використовується локальна змінна $i
$i = 4;
$j = 30;
print "f3[i,j]=[$i,$j]\n";
}
// тести
$i = 0;
$j = 0; // ці дві змінні невідомі функції f
// лише якщо вона явно оголошена за допомогою оператора global
// що вона хоче їх використовувати
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";
Результати:
Коментарі
- рядки 29–30: визначають 2 змінні $i та $j головної програми. Ці змінні не визнані всередині функцій. Так, у рядку 9 змінна $j функції f1 є локальною змінною функції f1 і відрізняється від змінної $j головної програми. Функція може отримати доступ до змінної $variable головної програми за допомогою ключового слова global;
- у рядку 7 оператор вказує на глобальну змінну $i головної програми;
3.4.2. Приклад 3
Скрипт [bases-03.php] має такий вигляд:
<?php
// область дії змінної є глобальною для блоків коду
$i = 0; {
$i = 4;
$i++;
}
print "i=$i\n";
Результати:
Коментарі
У деяких мовах програмування змінна, визначена в фігурних дужках, має область дії, обмежену цими дужками: вона не є відомою поза ними. Наведені вище результати показують, що в PHP це не так. Змінна $i, визначена в рядку 5 всередині фігурних дужок, є тією самою, що й та, яка використовується в рядках 4 та 8 поза ними.
3.5. Зміни типів
Змінні в PHP не мають постійного типу. Він може змінюватися під час виконання залежно від значення, присвоєного змінній. У операціях, що передбачають використання даних різних типів, інтерпретатор PHP виконує неявні перетворення, щоб привести операнди до спільного типу. Ці неявні перетворення, якщо про них не відомо розробнику, можуть стати джерелом помилок, які важко виявити. Нижче наведено скрипт [bases-04.php], що демонструє явні та неявні перетворення:
<?php
// суворі типи при передачі параметрів
declare(strict_types=1);
// неявні зміни типів
// тип -->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 : ";
// перетворення $var у логічне значення відбувається автоматично в наступному тесті
if ($var) {
print "true";
} else {
print "false";
}
print "\n";
}
Коментарі
- рядок 4: вимагає суворої перевірки типу параметрів функції, коли він вказаний;
- рядок 18: функція [showBool] призначена для демонстрації неявного (автоматичного) перетворення, яке виконує інтерпретатор PHP, коли значення будь-якого типу потрібно перетворити на логічне значення (рядок 21);
- рядок 18: параметру $var не присвоєно типу. Отже, фактичний параметр може бути будь-якого типу. Параметр $prefixe, у свою чергу, повинен бути типу string. Функція showBool не повертає жодного значення (void);
- рядок 21: в операторі if($var) значення $var має бути перетворено на логічне значення, щоб можна було обчислити if. Дивно, але інтерпретатор PHP має відповідь для будь-якого типу значення, яке йому надається;
- рядки 9–16: значення параметра функції [showBool] послідовно буде:
- рядок 9: непорожній рядок: результат TRUE (регістр не має значення, TRUE = true);
- рядок 10: порожній рядок: результат FALSE;
- рядок 11: непорожній масив: результат TRUE;
- рядок 12: порожній масив: результат FALSE;
- рядок 14: дійсне число 0: результат FALSE;
- рядок 15: ціле число 0: результат FALSE;
- рядок 16: дійсне (або ціле) число, відмінне від 0: результат TRUE;
Про це свідчать отримані екранні виводи:
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
Продовжимо код скрипта:
//
// неявні перетворення типу string у числовий тип
// рядок --> число
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";
}
Коментарі
- рядок 9: функція [showNumber] приймає параметр типу string і не повертає результату (void);
- рядок 10: цей параметр використовується в арифметичній операції, що змусить інтерпретатор PHP спробувати перетворити $var на число;
- рядок 5: перетворить рядок «12» на ціле число 12;
- рядок 6: перетворить рядок «45.67» на дійсне число 45.67;
- рядок 7: видасть попередження, але все одно перетворить рядок «abcd» на число 0;
Ось результати виконання:
Продовжимо код скрипта:
// явні зміни типу
// у ціле число
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";
}
Коментарі
- рядок 21: функція [showInt] приймає параметр будь-якого типу і не повертає результату. Вона намагається перетворити параметр $var на ціле число (рядок 26). Загалом, щоб перетворити змінну $var на тип T, записують (T) $var, де T може бути: int, integer, bool, boolean, float, double, real, string, array, object, unset;
- рядок 16: перетворює рядок «12.45» на ціле число 12;
- рядок 17: перетворює дійсне число 67.8 на ціле число 67;
- рядок 18: перетворює логічне значення TRUE на ціле число 1 (логічне значення FALSE — на ціле число 0);
- рядок 19: перетворює покажчик NULL на ціле число 0;
Це відображається на екрані:
Продовжуємо вивчення скрипта з явним перетворенням значень у тип float:
// у тип 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";
}
Коментарі
- рядок 35: функція [showFloat] приймає параметр будь-якого типу і не повертає результату;
- рядок 40: значення цього параметра явно перетворюється на float;
- рядок 30: рядок «12.45» перетворюється на дійсне число 12.45;
- рядок 31: ціле число 67 перетворюється на дійсне число 67;
- рядок 32: логічне значення TRUE перетворюється на дійсне число 1 (значення FALSE — на число 0);
- рядок 33: покажчик NULL перетворюється на дійсне число 0;
Про це свідчать результати на екрані:
Продовжуємо огляд скрипта, розглядаючи перетворення у тип string:
// у рядок
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";
}
- рядок 49: функція [showString] приймає параметр довільного типу і не повертає результату;
- рядок 54: значення параметра перетворюється на тип string;
- рядок 44: ціле число 5 буде перетворено на рядок «5»;
- рядок 45: дійсне число 6.7 буде перетворено на рядок «6.7»;
- рядок 46: логічне значення FALSE буде перетворено на порожній рядок;
- рядок 47: покажчик NULL буде перетворено на порожній рядок;
Ось результати на екрані:
3.6. Масиви
3.6.1. Класичні одновимірні масиви
Скрипт [bases-05.php] має такий вигляд:
<?php
// класичні масиви
// ініціалізація
$tab1 = array(0, 1, 2, 3, 4, 5);
// обхід — 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// обхід — 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1)) {
print "tab1[$clé]=$valeur\n";
}
// додавання елементів
$tab1[] = $i++;
$tab1[] = $i++;
// перегляд — 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
print "tab1[$i]=$élément\n";
$i++;
}
// видалення останнього елемента
array_pop($tab1);
// перегляд — 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// видалення першого елемента
array_shift($tab1);
// проходження — 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// додавання в кінець масиву
array_push($tab1, -2);
// пробіг — 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// додавання на початок масиву
array_unshift($tab1, -1);
// перегляд — 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
Результати:
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
Коментарі
Наведена вище програма демонструє операції з масивом значень. У PHP існують два способи запису масивів:
Масив 1 називається масивом, а масив 2 — словником або асоціативним масивом, де елементи позначаються у форматі «ключ => значення». Запис $contraires["beau"] позначає значення, пов’язане з ключем «красивий». У даному випадку це рядок «потворний». Масив 1 є лише варіантом словника і може бути записаний так:
Таким чином, маємо $tableau[2] = «trois». Зрештою, існують лише словники. У випадку класичного масиву, що містить n елементів, ключами є цілі числа з інтервалу [0,n-1].
- рядок 14: функція each($tableau) дозволяє обходити словник. При кожному виклику вона повертає пару (ключ, значення) з нього. Як показано в рядку 10 результатів, функція each відтепер є застарілою у PHP 7;
- рядок 13: функція reset($dictionnaire) встановлює функцію each для першої пари (ключ, значення) словника.
- рядок 14: цикл while зупиняється, коли функція each повертає порожню пару в кінці словника. Тут відбувається неявне перетворення: порожня пара перетворюється на логічне значення FALSE;
- рядок 18: запис $tableau[]=значення додає елемент valeur як останній елемент масиву $tableau;
- рядок 23: масив обходиться за допомогою foreach. Цей синтаксичний елемент дозволяє обходити словник, а отже й масив, за двома синтаксичними конструкціями:
Перший синтаксис повертає пару (clé,valeur) при кожній ітерації, тоді як другий синтаксис повертає лише елемент valeur зі словника.
- рядок 28: функція array_pop($tableau) видаляє останній елемент з $tableau;
- рядок 35: функція array_shift($tableau) видаляє перший елемент з $tableau;
- рядок 42: функція array_push($tableau, значення) додає valeur як останній елемент $tableau;
- рядок 49: функція array_unshift($tableau, значення) додає valeur як перший елемент масиву $tableau;
3.6.2. Словник або асоціативний масив
Скрипт [bases-06.php] має такий вигляд:
<?php
// словники
$conjoints = ["Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => ""];
// проходження — 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
print "conjoints[$clé]=$valeur\n";
}
// сортування словника за ключем
ksort($conjoints);
// пробіг — 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
print "conjoints[$clé]=$valeur\n";
}
// список ключів словника
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++) {
print "clés[$i]=$clés[$i]\n";
}
// список значень словника
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++) {
print "valeurs[$i]=$valeurs[$i]\n";
}
// пошук ключа
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// видалення пари «ключ-значення»
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
print "conjoints[$clé]=$valeur\n";
}
// кінець
exit;
function existe($conjoints, $mari) {
// перевіряє, чи існує ключ $mari у словнику $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";
}
}
Результати:
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
Коментарі
Попередній код застосовує до словника те, що ми розглядали раніше для простого масиву. Ми коментуємо лише нові елементи:
- рядок 12: функція ksort (key sort) дозволяє впорядкувати словник за природним порядком ключів;
- рядок 19: функція array_keys($dictionnaire) повертає список ключів словника у вигляді масиву;
- рядок 24: функція array_values($dictionnaire) повертає список значень словника у вигляді масиву;
- рядок 43: функція isset($variable) повертає TRUE, якщо змінна $variable була визначена, інакше — FALSE;
- рядок 33: функція unset($variable) видаляє змінну $variable.
3.6.3. Багатовимірні масиви
Скрипт [bases-07.php] має такий вигляд:
<?php
// класичні багатовимірні масиви
// ініціалізація
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// обхід
for ($i1 = 0; $i1 < count($multi); $i1++) {
for ($i2 = 0; $i2 < count($multi[$i1]); $i2++) {
print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
}
}
// багатовимірні словники
// ініціалізація
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// обхід
foreach ($multi as $clé => $valeur) {
for ($i2 = 0; $i2 < count($valeur); $i2++) {
print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
}
}
Результати:
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
Коментарі
- рядок 5: елементи масиву $multi самі є масивами;
- рядок 14: масив $multi перетворюється на словник (clé,valeur), де кожен valeur є масивом;
3.7. Символьні рядки
3.7.1. Означення
Скрипт [bases-08.php] має такий вигляд:
<?php
// запис рядків
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>
Результати:
3.7.2. Порівняння
Скрипт [bases-09.php] має такий вигляд:
<?php
// суворе дотримання типів параметрів функцій
declare(strict_types=1);
// функція порівняння
function compareModele2Chaine(string $chaine1, string $chaine2): void {
// порівнює рядок1 і рядок2
if ($chaine1 === $chaine2) {
print "[$chaine1] est égal à [$chaine2]\n";
} else {
print "[$chaine1] est différent de [$chaine2]\n";
}
}
// тести порівняння рядків
compareModele2Chaine("abcd", "abcd");
compareModele2Chaine("", "");
compareModele2Chaine("1", "");
exit;
Результати:
[abcd] est égal à [abcd]
[] est égal à []
[1] est différent de []
Коментарі
- 9-й рядок коду: можна було б використати оператор порівняння == замість ===. Останній оператор є більш обмежувальним, оскільки вимагає, щоб обидва операнди були одного типу. Варто зазначити, що в даному випадку його можна було б замінити на оператор ==, оскільки тип обох параметрів у сигнатурі функції задано як string;
3.7.3. Зв’язки між рядками та масивами
Скрипт [bases-10.php] має такий вигляд:
<?php
// перетворення рядка в масив
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// обхід масиву
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
}
// масив у рядок
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// додамо порожнє поле
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// обхід масиву
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
} // тепер у нас є 5 елементів, останній з яких порожній
// додамо ще одне порожнє поле
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// пробігаємо масив
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
} // тепер маємо 6 елементів, останні два з яких порожні
Результати:
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]=
Коментарі
- рядок 5: функція explode($séparateur,$chaine) дозволяє витягти поля з $chaine, розділені $séparateur. Так, функція explode(":",$chaine) дозволяє отримати у вигляді масиву елементи $chaine, розділені символом ":";
- рядок 12: функція implode($séparateur,$tableau) виконує операцію, протилежну до функції explode. Вона повертає рядок, утворений елементами $tableau, розділеними $séparateur;
3.7.4. Регулярні вирази
Скрипт [bases-11.php] має такий вигляд:
<?php
// строгий тип для параметрів функцій
declare (strict_types=1);
// регулярні вирази в PHP
// витяг різних полів із рядка
// шаблон: послідовність цифр, оточена довільними символами
// потрібно витягти лише послідовність цифр
$modèle = "/(\d+)/";
// порівнюємо рядок із шаблоном
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");
// шаблон: послідовність цифр, оточена довільними символами
// потрібна послідовність цифр, а також поля, що йдуть перед нею та після неї
$modèle = "/^(.*?)(\d+)(.*?)$/";
// порівнюємо рядок із шаблоном
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");
// шаблон — дата у форматі дд/мм/рр
$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");
// шаблон — десяткове число
$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");
// кінець
exit;
// --------------------------------------------------------------------------
function compareModele2Chaine(string $modèle, string $chaîne): void {
// порівнює рядок $chaîne із шаблоном $modèle
// рядок порівнюється з шаблоном
$champs = [];
$correspond = preg_match($modèle, $chaîne, $champs);
// виведення результатів
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";
}
}
Результати:
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
Коментарі
- тут ми використовуємо регулярні вирази для вилучення різних полів із символьного рядка. Регулярні вирази дозволяють обійти обмеження функції implode. Принцип полягає в порівнянні одного рядка символів з іншим рядком, який називається modèle, за допомогою функції preg_match:
$correspond = preg_match($modèle, $chaîne, $champs);
Функція preg_match повертає логічне значення TRUE, якщо modèle можна знайти в chaîne. Якщо так, то $champs[0] представляє підрядок, що відповідає шаблону. Крім того, якщо modèle містить підмоделі в дужках, то $champs[1] — це частина $chaîne, що відповідає першій підмоделі, $champs[2] — це фрагмент $chaîne, що відповідає 2-й підмоделі, тощо…
Розглянемо перший приклад. Шаблон визначено в рядку 10: він позначає послідовність однієї або декількох (+) цифр (\d), розміщених у будь-якому місці рядка. Крім того, шаблон визначає підшаблон, укладений у дужки;
- рядок 12: шаблон /(\d+)/ (послідовність однієї або декількох цифр у будь-якому місці рядка) порівнюється з рядком «xyz1234abcd». Бачимо, що підрядок 1234 відповідає шаблону. Отже, $champs[0] дорівнює «1234». Крім того, шаблон містить підшаблони в дужках. Отримаємо $champs[1] = «1234»;
- рядок 13: шаблон /(\d+)/ порівнюється з рядком «12 34». Бачимо, що підрядки 12 та 34 відповідають шаблону. Порівняння зупиняється на першому підрядку, що відповідає шаблону. Отже, отримаємо: $champs[0]=12 та $champs[1]=12;
- рядок 14: шаблон /(\d+)/ порівнюється з рядком «abcd». Збігів не знайдено;
Роз’яснимо шаблони, що використовуються далі в коді:
$modèle = "/^(.*?)(\d+)(.*?)$/";
відповідає початку рядка (^), потім 0 або більше (*) довільних символів (.), потім 1 або більше (+) цифр, а потім знову 0 або більше (*) довільних символів (.). Шаблон (.*) позначає 0 або більше довільних символів. Такий шаблон відповідатиме будь-якому рядку. Отже, шаблон /^(.*)(\d+)(.*)$/ ніколи не буде знайдений, оскільки перший підшаблон (.*) поглине весь рядок. Шаблон (.*?)(\d+) позначає 0 або більше довільних символів аж до наступного підшаблону (?), у даному випадку \d+. Отже, цифри тепер більше не поглинаються шаблоном (.*). Таким чином, наведений вище шаблон відповідає [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*$/";
відповідає [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*/";
відповідає початку рядка (^), 0 або більше пробілів (\s*), знаку + або - [+|-], що зустрічається 0 або 1 раз (?), послідовності 0 або більше пробілів (\s*), 1 або більше цифр, за якими йде десяткова крапка, за якою йдуть нуль або більше цифр (\d+\.\d*) або (|) десяткова крапка (\.) за якою йдуть одна або більше цифр (\d+) або (|) одна або більше цифр (\d+), послідовність 0 або більше пробілів (\s*)].
Примітка: термін [espace] у регулярних виразах позначає набір символів: пробіл, перехід на новий рядок \n, табуляція \t, повернення на початок рядка \r, перехід на нову сторінку \f…
3.8. Функції
3.8.1. Спосіб передачі параметрів
Скрипт [base-12.php] має такий вигляд:
<?php
// спосіб передачі параметрів функції
// суворе дотримання типів параметрів
declare(strict_types=1);
function f(int &$i, int $j): void {
// $i буде передано за посиланням
// $j буде отримано за значенням
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
// тести
$i = 0;
$j = 0;
// $i та $j передаються до функції f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
Результати:
Коментарі
Наведений вище код демонструє два способи передачі параметрів у функцію. Розглянемо такий приклад:
- рядок 1: визначає формальні параметри $a та $b функції f. Ця функція обробляє ці два формальні параметри та повертає результат;
- рядок 7: виклик функції f з двома фактичними параметрами $i та $j. Зв’язки між формальними параметрами ($a, $b) та фактичними параметрами ($i, $j) визначаються рядками 1 та 7:
- &$a: знак & вказує, що формальний параметр $a прийме за значення адресу фактичного параметра $i. Іншими словами, $a та $i — це дві посилання на одну й ту саму комірку пам’яті. Операції з формальним параметром $a еквівалентні операціям з фактичним параметром $i. Це підтверджується виконанням коду. Цей спосіб передачі підходить для вихідних параметрів та великих обсягів даних, таких як масиви та словники. Цей спосіб передачі називають передачею за посиланням.
- $b: формальний параметр $b прийме значення, яке має фактичний параметр $j. Це передача за значенням. Формальні та фактичні параметри — це дві різні змінні. Операції з формальним параметром $b жодним чином не впливають на фактичний параметр $j. Це підтверджується виконанням коду. Цей режим передачі підходить для вхідних параметрів.
- Розглянемо функцію échange, яка приймає два формальні параметри $a та $b. Функція міняє місцями значення цих двох параметрів. Отже, під час виклику з обміном ($i, $j) код, що викликає, очікує, що значення двох фактичних параметрів будуть поміняні місцями. Отже, це вихідні параметри (вони змінюються). Тому запишемо:
Наступний скрипт [base-13.php] демонструє інші приклади:
<?php
// типи в строгому режимі
// declare(strict_types = 1);
// спосіб передачі параметрів
function f(&$i, $j) {
// $i буде передано за посиланням
// $j буде передано за значенням
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
function g(int &$i, int $j) : void {
// $i буде отримано за посиланням
// $j буде отримано за значенням
$i++;
$j++;
print "g[i,j]=[$i,$j]\n";
}
// тести
$i = 0;
$j = 0;
// $i та $j передаються до функції f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
// $i та $j передаються до функції g
g($i, $j);
print "test[i,j]=[$i,$j]\n";
// функції f передаються неправильні параметри
$a=5.3;
$b=6.2;
f($a, $b);
print "test[a,b]=[$a,$b]\n";
// до функції f передаються неправильні параметри
$a=5.3;
$b=6.2;
g($a, $b);
print "test[a,b]=[$a,$b]\n";
Коментарі
- рядки 8–14: функція f, розглянута в попередньому параграфі, але типи параметрів не вказано;
- рядки 16–22: функція g робить те саме, що й функція f, але ми вказуємо типи очікуваних параметрів — це новинка PHP 7. Очікуються два параметри типу int. Ми хочемо побачити, що відбувається, коли фактичний параметр, переданий функції, не має типу, якого вона очікує;
- рядки 25–26: $i та $j — це два цілі числа;
- рядки 28–29: виклик функції f з параметрами очікуваного типу;
- рядки 31–32: виклик функції g з параметрами очікуваного типу;
- рядки 34–35: змінні $a та $b мають тип float;
- рядки 36–37: виклик функції f з параметрами, які не відповідають очікуваному типу;
- рядки 41–42: виклик функції g з параметрами, які не відповідають очікуваному типу;
Результати
- рядки 5–6 показують, що функція f прийняла обидва параметри типу float і працювала з ними;
- рядки 7–8 показують, що функція g прийняла обидва параметри типу float, але перетворила їх на тип int (рядок 7);
Тепер розкоментуємо рядок 4:
Ця інструкція вказує, що типи формальних параметрів мають відповідати заданим. Якщо це не так, з’являється повідомлення про помилку. Результати виконання тоді стають такими:
- рядки 9–10: інтерпретатор PHP 7 згенерував виняток, щоб вказати, що перший параметр, переданий функції g, мав неправильний тип. Рекомендується бути суворим щодо типів параметрів, коли це можливо, щоб виявляти помилки виклику функцій;
3.8.2. Результати, що повертаються функцією
Скрипт [base-15.php] має такий вигляд:
<?php
// типи в строгому режимі
declare(strict_types=1);
// результати, що повертаються функцією
// функція може повертати кілька значень у масиві
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";
}
// функція може повертати об’єкт
$res = f2(10);
print "f2 : [$res->res1,$res->res2,$res->res3]\n";
// об’єкт якого типу?
print "nature de l'objet : ";
var_dump($res);
print "\n";
// те саме робимо з функцією f3
$res = f3(10);
print "f3 : [$res->res1,$res->res2,$res->res3]\n";
// об’єкт якого типу?
print "nature de l'objet : ";
var_dump($res);
print "\n";
// кінець
exit;
// функція f1
function f1(int $valeur): array {
// повертає масив ($valeur+1,$valeur+2,$valeur+3)
return array($valeur + 1, $valeur + 2, $valeur + 3);
}
// функція f2
function f2(int $valeur): object {
// повертає об’єкт ($valeur+1,$valeur+2,$valeur+3)
$res->res1 = $valeur + 1;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// повертає об’єкт
return $res;
}
// функція f3 — виконує те саме, що й функція f2
function f3(int $valeur): object {
// повертає об’єкт ($valeur+1,$valeur+2,$valeur+3)
$res = new stdclass();
$res->res1 = $valeur + 1;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// повертає об’єкт
return $res;
}
Результати
[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)
}
Коментарі
- попередня програма показує, що функція PHP може повертати не один, а набір результатів у вигляді масиву або об’єкта. Поняття об’єкта пояснюється трохи далі;
- рядки 35–38: функція f1 повертає кілька значень у вигляді масиву (array);
- рядки 41–48: функція f2 повертає кілька значень у вигляді об’єкта (object);
- рядки 51–59: функція f3 ідентична функції f2, за винятком того, що вона явно створює об’єкт у рядку 53;
- у рядку 6 результатів з’являється попередження (warning), яке вказує, що PHP був змушений створити об’єкт за замовчуванням у рядку 43 коду, тобто під час використання нотації [$res→res1]. Функція var_dump у рядку 20 коду надає доступ до типу об’єкта та його вмісту. У результатах видно, що:
- рядок 8: об’єкт, створений за замовчуванням, має тип stdClass;
- рядки 9–10: властивість res1 має тип entier і значення 11;
- тощо…
- щоб уникнути попередження у рядку 6 результатів, у рядку 53 функції f3 явно створюємо об’єкт типу stdClass;
3.9. Текстові файли
Скрипт [bases-16.php] має такий вигляд:
<?php
// суворе дотримання типів параметрів функцій
declare (strict_types=1);
// послідовна обробка текстового файлу
// цей файл є набором рядків у форматі login:pwd:uid:gid:infos:dir:shell
// кожен рядок заноситься до словника у вигляді login => uid:gid:infos:dir:shell
// визначається ім’я файлу
$INFOS = "infos.txt";
// файл відкривається для створення
if (!$fic = fopen($INFOS, "w")) {
print "Erreur d'ouverture du fichier $INFOS en écriture\n";
exit;
}
// генерується довільний вміст
for ($i = 0; $i < 100; $i++) {
fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
}
// файл закривається
fclose($fic);
// використовуємо його — fgets зберігає маркер кінця рядка
// це дозволяє уникнути отримання порожнього рядка під час читання порожнього рядка
// файл відкривається для читання
if (!$fic = fopen($INFOS, "r")) {
print "Erreur d'ouverture du fichier $INFOS en lecture\n";
exit;
}
// рядки містять менше 1000 символів
// читання рядка зупиняється на позначці кінця рядка
// або на позначці кінця файлу
while ($ligne = fgets($fic, 1000)) {
// видаляється маркер кінця рядка, якщо він існує
$ligne = cutNewLineChar($ligne);
// вставляємо рядок у таблицю
$infos = explode(":", $ligne);
// отримуємо логін
$login = array_shift($infos);
// ігноруємо пароль
array_shift($infos);
// створюємо запис у словнику
$dico[$login] = $infos;
}
// закриваємо його
fclose($fic);
// використання словника
afficheInfos($dico, "login10");
afficheInfos($dico, "X");
// кінець
exit;
// --------------------------------------------------------------------------
function afficheInfos(array $dico, string $clé): void {
// виводить значення, пов'язане з ключем у словнику $dico, якщо воно існує
if (isset($dico[$clé])) {
// значення існує — чи це масив?
$valeur = $dico[$clé];
if (is_array($valeur)) {
print "[$clé," . join(":", $valeur) . "]\n";
} else {
// $valeur не є масивом
print "[$clé,$valeur]\n";
}
} else {
// $clé не є ключем словника $dico
print "la clé [$clé] n'existe pas\n";
}
}
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
// видаляється позначка кінця рядка з $ligne, якщо вона існує
$L = strlen($ligne); // довжина рядка
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// кінець
return($ligne);
}
Файл infos.txt:
Результати:
[login10,uid10:gid10:infos10:dir10:shell10]
la clé [X] n'existe pas
Коментарі
- рядок 12: fopen(nom_fichier, "w") відкриває файл nom_fichier для запису (w=write). Якщо файл не існує, його створюють. Якщо він існує, його вміст очищують. Якщо створення файлу не вдається, fopen повертає значення false. В операторі if (!$fic = fopen($INFOS, "w")) {…} виконуються дві послідовні операції: 1) $fic = fopen(..) 2) if( ! $fic) {…};
- рядок 18: fputs($fic,$chaîne) записує chaîne у файл $fic. $chaine записується з символом кінця рядка \n наприкінці;
- рядок 21: fclose($fic) закриває файл $fic;
- рядок 26: fopen(nom_fichier,"r") відкриває файл nom_fichier для читання (r=read). Якщо відкриття не вдається (наприклад, файл не існує), fopen повертає значення false;
- рядок 34: fgets($fic, 1000) зчитує наступний рядок з файлу, обмежуючи його довжину 1000 символами. В операторі while ($ligne = fgets($fic, 1000)) {…} виконуються дві послідовні операції: 1) $ligne = fgets(…) 2) while ( ! $ligne). Після того, як прочитано останній символ файлу, функція fgets повертає значення false, і цикл while зупиняється. Функція fgets намагається прочитати не більше 1000 символів, але зупиняється, щойно зустрічає маркер кінця рядка. Оскільки тут усі рядки містять менше 1000 символів, [fgets] зчитує один рядок тексту, включаючи символ кінця рядка. Функція cutNewLineChar у рядках 75–84 видаляє можливі символи кінця рядка;
- рядок 77: функція strlen($chaîne) повертає кількість символів у $chaîne;
- рядок 78: функція substr($ligne, $position, $taille) повертає $taille символів з $ligne, починаючи з символу № $position, причому перший символ має номер 0. На комп’ютерах з ОС Windows позначкою кінця рядка є «\r\n». На комп’ютерах з ОС Unix — це рядок «\n»;
- рядок 40: функція array_shift($tableau) видаляє перший елемент з $tableau і повертає його як результат. Тут не враховується результат, повернений функцією array_shift;
- рядок 62: функція is_array($variable) повертає true, якщо $variable є масивом, інакше — false;
- рядок 63: функція join виконує те саме, що й функція implode, яку ми вже розглядали;
3.10. Кодування / декодування jSON

Кодування / декодування jSON (JavaScript Object Notation) — це те, що ми будемо активно використовувати у вправі, яка є провідною темою цього документа. Скрипти [json-01.php, json-02.php, json-03.php] пояснюють, що потрібно знати для подальшої роботи.
Скрипт [json-01.php] має такий вигляд:
<?php
$array1 = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34];
// кодування масиву array1 у форматі JSON з екранованими символами Unicode
print "encodage json du tableau array1 avec caractères Unicode échappés\n";
$json1 = json_encode($array1);
print "json1=$json1\n";
// кодування JSON масиву array1 із символами 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";
// декодування jSON в асоціативний масив
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";
}
// декодування jSON в об’єкт
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";
Результати
Коментарі
- 6-й рядок коду: функція [json_encode] перетворює свій параметр на рядок jSON;
- 2-й рядок результатів: отриманий рядок jSON. Символи Unicode éâ були замінені на їхні коди Unicode, що починаються з \u;
- рядок 10 коду: повторюємо те саме, але цього разу вказуємо, щоб символи Unicode збереглися без змін;
- 4-й рядок результатів: отримано рядок jSON. Він набагато легший для читання;
- рядки 14–18 коду: виконуємо зворотну операцію. Перетворюємо рядок jSON на асоціативний масив;
- рядки 6–13 результатів: бачимо, що отримано асоціативний масив;
- рядки 19–25 коду: перетворюємо рядок jSON на об’єкт типу [stdClass];
- рядки 18–25 результатів: бачимо, що отримано об’єкт типу [stdClass];
- рядки 23–25 коду: атрибут A об’єкта O позначається як [O→A];
У форматі jSON можна кодувати багаторівневі масиви, як показано в наступному скрипті [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],
]];
// кодування jSON багаторівневого масиву
print "encodage jSON d'un tableau à plusieurs niveaux\n";
$json = json_encode($array, JSON_UNESCAPED_UNICODE);
print "json=$json\n";
Результати
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}]}
Коментарі
У рядку jSON:
- неасоціативні масиви взяті в квадратні дужки [] ;
- асоціативні масиви взяті в фігурні дужки {};
Скрипт [json-03.php] демонструє, як використовувати наступний файл 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
}
]
}
Скрипт [json-03.php] має такий вигляд:
<?php
// читання файлу jSON
$json = file_get_contents("famille.json");
// декодування JSON в об’єкт
$famille1 = json_decode($json);
print "----famille1\n";
var_dump($famille1);
// декодування JSON у асоціативний масив
print "----famille2\n";
$famille2 = json_decode($json, true);
var_dump($famille2);
Коментарі
- рядок 4: функція [file_get_contents] зчитує вміст файлу з іменем [famille.json] і зберігає його у змінній [$json];
- потім змінна декодується в об’єкт (рядки 5–8) та асоціативний масив (рядки 9–12);
Результати
----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)
}
}
}
Коментарі
- рядки 1–38: об’єкт, отриманий у результаті декодування файлу jSON [famille.json];
- рядки 39–76: асоціативний масив, отриманий у результаті декодування файлу jSON [famille.json];