Strings
Оновлено: 12.05.2023
Рядок - це послідовність символів, де символ дорівнює байту. Це означає, що PHP підтримує тільки 256-символьний набір, а отже, не пропонує власної підтримки Unicode. Детальніше про тип рядка див. у розділі "Рядок".
Примітка: У 32-бітних збірках рядок може мати розмір до 2 ГБ (максимум 2147483647 байт)
Рядковий літерал можна вказати чотирма різними способами:
- одинарні лапки
- подвійні лапки
- синтаксис heredoc
- синтаксис nowdoc
Найпростіший спосіб вказати рядок - взяти його в одинарні лапки (символ ').
Щоб вказати буквальну одинарну лапку, екрануйте її зворотною косою рискою (\). Щоб вказати буквальну зворотну косу риску, подвойте її (\\). Усі інші випадки зворотної косої риски вважатимуться буквальною зворотною косою рискою: це означає, що інші екрановані послідовності, до яких ви могли б звикнути, наприклад \r або \n, буде виведено буквально як вказано, а не з якимось особливим значенням.
Зауваження: На відміну від синтаксису подвійних лапок та heredoc, змінні та екрановані послідовності для спеціальних символів не розширюються, якщо вони зустрічаються у рядках з одинарними лапками.
<?php
echo 'this is a simple string';
echo 'You can also have embedded newlines in
strings this way as it is
okay to do';
// Outputs: Arnold once said: "I'll be back"
echo 'Arnold once said: "I\'ll be back"';
// Outputs: You deleted C:\*.*?
echo 'You deleted C:\\*.*?';
// Outputs: You deleted C:\*.*?
echo 'You deleted C:\*.*?';
// Outputs: This will not expand: \n a newline
echo 'This will not expand: \n a newline';
// Outputs: Variables do not $expand $either
echo 'Variables do not $expand $either';
?>
Якщо рядок взято в подвійні лапки (""), PHP інтерпретує наступні екрановані послідовності для спеціальних символів:
\n
\r
\t
\v
\e
\f
\\
\$
\"
\[0-7]{1,3}
\x[0-9A-Fa-f]{1,2}
\u{[0-9A-Fa-f]+}
Як і в рядках з одинарними лапками, екранування будь-якого іншого символу призведе до того, що зворотна коса риска також буде надрукована.
Найважливішою особливістю рядків у подвійних лапках є те, що імена змінних буде розширено. Дивіться розбір рядків для більш детальної інформації.
Третім способом розділення рядків є синтаксис heredoc: <<<. Після цього оператора вказується ідентифікатор, потім новий рядок. Далі йде сам рядок, а потім знову той самий ідентифікатор, щоб закрити лапки.
Ідентифікатор завершення може мати відступ за допомогою пробілу або табуляції, у цьому випадку відступ буде знято з усіх рядків у рядку doc. До версії PHP 7.3.0 ідентифікатор закриття повинен починатися у першому стовпчику рядка.
Крім того, закриваючий ідентифікатор повинен відповідати тим же правилам іменування, що і будь-яка інша мітка в PHP: він повинен містити тільки алфавітно-цифрові символи і символи підкреслення, і повинен починатися з нецифрового символу або символу підкреслення.
Приклад #1 Базовий приклад Heredoc з PHP 7.3.0
<?php
// no indentation
echo <<<END
a
b
c
\n
END;
// 4 spaces of indentation
echo <<<END
a
b
c
END;
Якщо закриваючий ідентифікатор має відступ більше, ніж будь-який рядок тіла, то буде згенеровано ParseError:
Приклад #2 Закриваючий ідентифікатор не повинен мати відступів далі, ніж будь-які рядки тіла
<?php
echo <<<END
a
b
c
END;
Якщо закриваючий ідентифікатор має відступ, можна також використовувати табуляцію, однак табуляція і пробіли не повинні змішуватися з відступом закриваючого ідентифікатора і відступом тіла (до закриваючого ідентифікатора). У будь-якому з цих випадків буде згенеровано помилку розбору (ParseError). Ці обмеження щодо пробілів було включено, оскільки змішування табуляцій і пробілів для відступів шкодить читабельності.
Приклад #3 Інший відступ для закриваючого ідентифікатора тіла (пробіли)
<?php
// All the following code do not work.
// different indentation for body (spaces) ending marker (tabs)
{
echo <<<END
a
END;
}
// mixing spaces and tabs in body
{
echo <<<END
a
END;
}
// mixing spaces and tabs in ending marker
{
echo <<<END
a
END;
}
Приклад #4 Продовження виразу після закриваючого ідентифікатора
<?php
$values = [<<<END
a
b
c
END, 'd e f'];
var_dump($values);
Якщо закриваючий ідентифікатор було знайдено на початку рядка, то незалежно від того, чи є він частиною іншого слова, він може розглядатися як закриваючий ідентифікатор і спричинити помилку синтаксичного аналізу.
Приклад #5 Закриття ідентифікатора в тілі рядка може призвести до ParseError
<?php
$values = [<<<END
a
b
END ING
END, 'd e f'];
Щоб уникнути цієї проблеми, ви можете дотримуватися простого правила: не вибирати ідентифікатор закриття, який з'являється в тексті.
До версії PHP 7.3.0 дуже важливо звернути увагу на те, що рядок із закриваючим ідентифікатором не повинен містити жодних інших символів, окрім крапки з комою (;). Це означає, зокрема, що ідентифікатор не повинен мати відступів, а перед або після крапки з комою не повинно бути пробілів або табуляції. Також важливо розуміти, що перший символ перед ідентифікатором, що закривається, має бути переведенням рядка, як це визначено локальною операційною системою. У системах UNIX, включаючи macOS, це \n. Після закриваючого роздільника також має стояти новий рядок.
Якщо це правило порушено і закриваючий ідентифікатор не є "чистим", він не буде вважатися закриваючим ідентифікатором, і PHP продовжить його пошук. Якщо правильний закриваючий ідентифікатор не буде знайдено до кінця поточного файлу, в останньому рядку буде видано помилку розбору.
Приклад #6 Неправильний приклад, до версії PHP 7.3.0
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
// Identifier must not be indented
?>
Приклад #7 Коректний приклад, навіть якщо версія PHP 7.3.0
<?php
class foo {
public $bar = <<<EOT
bar
EOT;
}
?>
Для ініціалізації властивостей класу не можна використовувати спадкові файли, що містять змінні.
Текст heredoc поводиться так само, як рядок у подвійних лапках, але без подвійних лапок. Це означає, що лапки у heredoc не потрібно екранувати, але можна використовувати перелічені вище коди екранування. Змінні розширюються, але при вираженні складних змінних у heredoc слід дотримуватися тієї ж обережності, що і при вираженні рядків.
Приклад #8 Приклад цитування рядка Heredoc
<?php
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
/* More complex example, with variables. */
class foo
{
var $foo;
var $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;
?>
Також можна використовувати синтаксис Heredoc для передачі даних в аргументи функції:
Приклад #9 Приклад Heredoc в аргументах
<?php
var_dump(array(<<<EOD
foobar!
EOD
));
?>
Ініціалізувати статичні змінні та властивості/константи класу можна за допомогою синтаксису Heredoc:
Приклад #10 Використання Heredoc для ініціалізації статичних значень
<?php
// Static variables
function foo()
{
static $bar = <<<LABEL
Nothing in here...
LABEL;
}
// Class properties/constants
class foo
{
const BAR = <<<FOOBAR
Constant example
FOOBAR;
public $baz = <<<FOOBAR
Property example
FOOBAR;
}
?>
Відкриваючий ідентифікатор Heredoc можна за бажанням взяти у подвійні лапки:
Приклад #11 Використання подвійних лапок у Heredoc
<?php
echo <<<"FOOBAR"
Hello World!
FOOBAR;
?>
Nowdoc - це те саме, що heredoc для рядків в одинарних лапках, а heredoc для рядків у подвійних лапках. Nowdoc вказується так само, як і heredoc, але всередині nowdoc не виконується синтаксичний аналіз. Ця конструкція ідеально підходить для вбудовування PHP-коду або інших великих блоків тексту без необхідності екранування. Вона має деякі спільні риси з конструкцією SGML , оскільки оголошує блок тексту, який не підлягає синтаксичному аналізу.
Nowdoc ідентифікується за допомогою тієї ж послідовності <<<, що використовується для heredoc, але ідентифікатор, який слідує за ним, береться в одинарні лапки, наприклад, <<<'EOT'. Усі правила для ідентифікаторів heredoc також застосовуються до ідентифікаторів nowdoc, особливо ті, що стосуються зовнішнього вигляду закриваючого ідентифікатора.
Приклад #12 Приклад цитування рядка Nowdoc
<?php
echo <<<'EOD'
Example of string spanning multiple lines
using nowdoc syntax. Backslashes are always treated literally,
e.g. \\ and \'.
EOD;
Приклад #13 Приклад цитування рядка Nowdoc зі змінними
<?php
class foo
{
public $foo;
public $bar;
function __construct()
{
$this->foo = 'Foo';
$this->bar = array('Bar1', 'Bar2', 'Bar3');
}
}
$foo = new foo();
$name = 'MyName';
echo <<<'EOT'
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should not print a capital 'A': \x41
EOT;
?>
Приклад #14 Приклад статичних даних
<?php
class foo {
public $bar = <<<'EOT'
bar
EOT;
}
?>
Коли рядок вказано у подвійних лапках або за допомогою heredoc, змінні розбираються всередині нього.
Існує два типи синтаксису: простий і складний. Простий синтаксис є найбільш поширеним і зручним. Він дозволяє вбудувати змінну, значення масиву або властивість об'єкта в рядок з мінімальними зусиллями.
Складний синтаксис можна розпізнати за фігурними дужками, що оточують вираз.
Якщо зустрічається знак долара ($), синтаксичний аналізатор буде жадібно брати якомога більше лексем, щоб сформувати правильне ім'я змінної. Візьміть ім'я змінної у фігурні дужки, щоб явно вказати кінець імені.
<?php
$juice = "apple";
echo "He drank some $juice juice.".PHP_EOL;
// Invalid. "s" is a valid character for a variable name, but the variable is $juice.
echo "He drank some juice made of $juices.";
// Valid. Explicitly specify the end of the variable name by enclosing it in braces:
echo "He drank some juice made of ${juice}s.";
?>
Аналогічно можна аналізувати індекс масиву або властивість об'єкта. В індексах масивів кінець індексу позначається квадратною дужкою (]), що закривається. До властивостей об'єктів застосовуються ті ж правила, що і до простих змінних.
Приклад #15 Простий приклад синтаксису
<?php
$juices = array("apple", "orange", "koolaid1" => "purple");
echo "He drank some $juices[0] juice.".PHP_EOL;
echo "He drank some $juices[1] juice.".PHP_EOL;
echo "He drank some $juices[koolaid1] juice.".PHP_EOL;
class people {
public $john = "John Smith";
public $jane = "Jane Smith";
public $robert = "Robert Paulsen";
public $smith = "Smith";
}
$people = new people();
echo "$people->john drank some $juices[0] juice.".PHP_EOL;
echo "$people->john then said hello to $people->jane.".PHP_EOL;
echo "$people->john's wife greeted $people->robert.".PHP_EOL;
echo "$people->robert greeted the two $people->smiths."; // Won't work
?>
Починаючи з версії PHP 7.1.0 підтримуються також від'ємні числові індекси.
Приклад #16 Від'ємні числові індекси
<?php
$string = 'string';
echo "The character at index -2 is $string[-2].", PHP_EOL;
$string[-3] = 'o';
echo "Changing the character at index -3 to o gives $string.", PHP_EOL;
?>
Для чогось складнішого слід використовувати складний синтаксис.
Він називається складним не тому, що синтаксис складний, а тому, що дозволяє використовувати складні вирази.
За допомогою цього синтаксису можна включити будь-яку скалярну змінну, елемент масиву або властивість об'єкта з рядковим представленням. Вираз записується так само, як він виглядав би поза рядком, а потім обгортається у { та }. Оскільки { не можна екранувати, цей синтаксис буде розпізнано лише тоді, коли $ стоїть одразу після {. Використовуйте {\$, щоб отримати літерал {$. Кілька прикладів для наочності:
<?php
// Show all errors
error_reporting(E_ALL);
$great = 'fantastic';
// Won't work, outputs: This is { fantastic}
echo "This is { $great}";
// Works, outputs: This is fantastic
echo "This is {$great}";
// Works
echo "This square is {$square->width}00 centimeters broad.";
// Works, quoted keys only work using the curly brace syntax
echo "This works: {$arr['key']}";
// Works
echo "This works: {$arr[4][3]}";
// This is wrong for the same reason as $foo[bar] is wrong outside a string.
// In other words, it will still work, but only because PHP first looks for a
// constant named foo; an error of level E_NOTICE (undefined constant) will be
// thrown.
echo "This is wrong: {$arr[foo][3]}";
// Works. When using multi-dimensional arrays, always use braces around arrays
// when inside of strings
echo "This works: {$arr['foo'][3]}";
// Works.
echo "This works: " . $arr['foo'][3];
echo "This works too: {$obj->values[3]->name}";
echo "This is the value of the var named $name: {${$name}}";
echo "This is the value of the var named by the return value of getName(): {${getName()}}";
echo "This is the value of the var named by the return value of \$object->getName(): {${$object->getName()}}";
// Won't work, outputs: This is the return value of getName(): {getName()}
echo "This is the return value of getName(): {getName()}";
// Won't work, outputs: C:\folder\{fantastic}.txt
echo "C:\folder\{$great}.txt"
// Works, outputs: C:\folder\fantastic.txt
echo "C:\\folder\\{$great}.txt"
?>
За допомогою цього синтаксису також можна отримати доступ до властивостей класу за допомогою змінних у рядках.
<?php
class foo {
var $bar = 'I am bar.';
}
$foo = new foo();
$bar = 'bar';
$baz = array('foo', 'bar', 'baz', 'quux');
echo "{$foo->$bar}\n";
echo "{$foo->{$baz[1]}}\n";
?>
Зауважте:
Значення, до якого звертаються з функцій, викликів методів, статичних змінних класу та констант класу всередині {$}, буде інтерпретовано як ім'я змінної в області видимості, в якій визначено рядок. Використання одинарних фігурних дужок ({}) не працюватиме для доступу до значень, що повертаються функціями або методами, а також до значень констант класу або статичних змінних класу.
<?php
// Show all errors.
error_reporting(E_ALL);
class beers {
const softdrink = 'rootbeer';
public static $ale = 'ipa';
}
$rootbeer = 'A & W';
$ipa = 'Alexander Keith\'s';
// This works; outputs: I'd like an A & W
echo "I'd like an {${beers::softdrink}}\n";
// This works too; outputs: I'd like an Alexander Keith's
echo "I'd like an {${beers::$ale}}\n";
?>
Доступ до символів у рядках можна отримати і змінити, вказавши нульове зміщення потрібного символу після рядка за допомогою квадратних дужок масиву, як у $str[42]. Для цього сприймайте рядок як масив символів. Функції substr() і substr_replace() можна використовувати, якщо потрібно вилучити або замінити більше ніж 1 символ.
Зауваження: Починаючи з версії PHP 7.1.0, підтримуються також від'ємні зміщення рядків. Вони визначають зміщення від кінця рядка. Раніше від'ємні зміщення видавали E_NOTICE при читанні (що призводило до появи порожнього рядка) і E_WARNING при записі (що залишало рядок недоторканим).
Зауваження: До версії PHP 8.0.0 доступ до рядків також можна було отримати за допомогою фігурних дужок, як у $str{42}, з тією ж метою. Цей синтаксис фігурних дужок було застарілим у PHP 7.4.0 і більше не підтримується у PHP 8.0.0.
При записі у зміщення за межами діапазону рядок доповнюється пробілами. Нецілі типи конвертуються в цілі. Заборонений тип зсуву видає E_WARNING. Використовується лише перший символ присвоюваного рядка. Починаючи з версії PHP 7.1.0, присвоєння порожнього рядка призводить до фатальної помилки. Раніше присвоювався байт NULL.
Внутрішньо рядки PHP є байтовими масивами. Як наслідок, доступ до рядка або його модифікація за допомогою дужок масиву не є безпечною для багатобайтових масивів, і її слід виконувати лише з рядками в однобайтовому кодуванні, наприклад, ISO-8859-1.
Зауваження: Починаючи з версії PHP 7.1.0, застосування оператора порожнього індексу до порожнього рядка призводить до фатальної помилки. Раніше порожній рядок автоматично перетворювався на масив.
Приклад #17 Деякі приклади рядків
<?php
// Get the first character of a string
$str = 'This is a test.';
$first = $str[0];
// Get the third character of a string
$third = $str[2];
// Get the last character of a string.
$str = 'This is still a test.';
$last = $str[strlen($str)-1];
// Modify the last character of a string
$str = 'Look at the sea';
$str[strlen($str)-1] = 'e';
?>
Зміщення рядків мають бути цілими або цілочисельними, інакше буде видано попередження.
Приклад #18 Приклад незаконних зсувів рядків
<?php
$str = 'abc';
var_dump($str['1']);
var_dump(isset($str['1']));
var_dump($str['1.0']);
var_dump(isset($str['1.0']));
var_dump($str['x']);
var_dump(isset($str['x']));
var_dump($str['1x']);
var_dump(isset($str['1x']));
?>
Зауважте:
Доступ до змінних інших типів (за винятком масивів або об'єктів, що реалізують відповідні інтерфейси) за допомогою [] або {} мовчки повертає нуль.
Зауважте:
Доступ до символів у рядкових літералах можна отримати за допомогою символів [] або {}.
Зауважте:
Доступ до символів у рядкових літералах за допомогою синтаксису {} було застарілим у PHP 7.4. Це було вилучено в PHP 8.0.
Рядки можна об'єднувати за допомогою оператора '.' (крапка). Зверніть увагу, що оператор '+' (додавання) для цього не працює. Докладнішу інформацію наведено у розділі Рядкові оператори.
Існує ряд корисних функцій для маніпуляцій з рядками.
Загальні функції описано у розділі рядкових функцій, а функції регулярних виразів, сумісні з Perl, - у розділі розширених функцій пошуку і заміни.
Також є функції для рядків URL і функції для шифрування/дешифрування рядків (Sodium і Hash).
Нарешті, дивіться також функції символьних типів.
Значення можна перетворити в рядок за допомогою приведення до (рядка) або функції strval(). Перетворення в рядок відбувається автоматично в області видимості виразу, де потрібен рядок. Це відбувається при використанні функцій echo або print, або коли змінна порівнюється з рядком. Розділи Типи та Жонглювання типами зроблять наступне зрозумілішим. Дивіться також функцію settype().
Значення bool true перетворюється на рядок "1". bool false перетворюється на "" (порожній рядок). Це дозволяє конвертувати значення типу bool у значення типу string і навпаки.
Число типу int або float перетворюється у рядок, що представляє число у текстовому вигляді (включаючи експоненціальну частину для чисел з плаваючою комою). Числа з плаваючою комою можуть бути перетворені з використанням експоненціального запису (4.1E+6).
Зауважте:
Починаючи з версії PHP 8.0.0, символом десяткової крапки завжди є крапка ("."). До версії PHP 8.0.0 символ десяткової крапки визначався у локалі скрипта (категорія LC_NUMERIC). Зверніться до функції setlocale().
Масиви завжди перетворюються в рядок "Array"; через це echo і print не можуть самі по собі показати вміст масиву. Щоб переглянути окремий елемент, використовуйте конструкцію типу echo $arr['foo']. Поради щодо перегляду всього вмісту дивіться нижче.
Для перетворення об'єктів у рядок слід використовувати магічний метод __toString.
Ресурси завжди перетворюються в рядки зі структурою "Ідентифікатор ресурсу #1", де 1 - це номер ресурсу, присвоєний йому PHP під час виконання. Хоча на точну структуру цього рядка не слід покладатися і вона може змінюватися, він завжди буде унікальним для даного ресурсу протягом усього часу виконання скрипта (тобто веб-запиту або CLI-процесу) і не буде використовуватися повторно. Щоб отримати тип ресурсу, скористайтеся функцією get_resource_type().
null завжди перетворюється на порожній рядок.
Як зазначалося вище, безпосереднє перетворення масиву, об'єкта або ресурсу у рядок не надає жодної корисної інформації про значення, окрім його типу. Більш ефективні засоби перевірки вмісту цих типів описано у функціях print_r() і var_dump().
Більшість значень PHP також можна перетворити на рядки для постійного зберігання. Цей метод називається серіалізацією і виконується функцією serialize().
Рядок у PHP реалізовано як масив байт і цілого числа, що вказує на довжину буфера. Він не містить інформації про те, як ці байти перетворюються на символи, залишаючи цю задачу програмісту. Немає жодних обмежень на значення, з яких може складатися рядок; зокрема, байти зі значенням 0 ("NUL байти") допускаються в будь-якому місці рядка (однак, деякі функції, які в цьому посібнику не вважаються "бінарно безпечними", можуть передавати рядки бібліотекам, які ігнорують дані після NUL байта).
Така природа рядкового типу пояснює, чому в PHP немає окремого типу "байт" - цю роль виконують рядки. Функції, які не повертають текстові дані - наприклад, довільні дані, прочитані з мережевого сокета - все одно повертатимуть рядки.
Враховуючи, що PHP не диктує конкретного кодування рядків, може виникнути питання про те, як кодуються рядкові літерали. Наприклад, чи еквівалентний рядок "á" "\xE1" (ISO-8859-1), "\xC3\xA1" (UTF-8, форма C), "\x61\xCC\x81" (UTF-8, форма D) або будь-якому іншому можливому представленню? Відповідь полягає в тому, що рядок буде закодовано так, як він закодований у файлі скрипта. Таким чином, якщо скрипт написаний в ISO-8859-1, то рядок буде закодовано в ISO-8859-1 і так далі. Однак це не стосується випадків, коли увімкнено Zend Multibyte; у такому випадку скрипт може бути записано у довільному кодуванні (яке явно оголошено або визначено), а потім перетворено у певне внутрішнє кодування, яке потім буде використано для рядкових літералів. Зауважте, що на кодування скрипта (або на внутрішнє кодування, якщо увімкнено Zend Multibyte) накладаються певні обмеження - це майже завжди означає, що це кодування має бути сумісною підмножиною ASCII, наприклад, UTF-8 або ISO-8859-1. Зауважте, однак, що залежні від стану кодування, у яких ті самі значення байтів можуть використовуватися у початковому і не початковому станах зсуву, можуть бути проблематичними.
Звичайно, для того, щоб бути корисними, функції, які працюють з текстом, повинні робити деякі припущення про те, як закодовано рядок. На жаль, у функціях PHP існує багато варіацій з цього приводу:
Деякі функції припускають, що рядок закодовано у деякому (будь-якому) однобайтовому кодуванні, але їм не потрібно інтерпретувати ці байти як певні символи. Такими функціями є, наприклад, substr(), strpos(), strlen() або strcmp(). Інший спосіб розглядати ці функції - це оперування з буферами пам'яті, тобто робота з байтами та зсувами байтів. Іншим функціям передається кодування рядка, можливо, вони також приймають значення за замовчуванням, якщо такої інформації не надано. Це випадок htmlentities() і більшості функцій у розширенні mbstring. Інші використовують поточну локаль (див. setlocale()), але працюють з байтами. Нарешті, вони можуть просто припускати, що рядок використовується у певному кодуванні, зазвичай UTF-8. Це стосується більшості функцій у розширенні intl та у розширенні PCRE (в останньому випадку, лише коли використовується модифікатор u).
Зрештою, це означає, що написання коректних програм з використанням Unicode залежить від ретельного уникнення функцій, які не працюватимуть і, швидше за все, пошкодять дані, і використання замість них функцій, які поводяться коректно, як правило, з розширень intl і mbstring. Однак використання функцій, які можуть працювати з кодуваннями Unicode, - це лише початок. Незалежно від того, які функції надає мова, важливо знати специфікацію Unicode. Наприклад, програма, яка вважає, що існують лише великі та малі літери, робить помилкове припущення.