PHP: Слабая типизация
Нам известно про два разных типа данных: числа и строки. Мы могли складывать числа, потому что операция сложения — это операция для типа «числа». А что, если применить эту операцию к числу и строке?
<?php
print_r(1 + '7'); // => 8'7' — это строка, а не число, при этом интерпретатор PHP выдал ответ 8, как если бы мы складывали два числа. Когда PHP видит несоответствие типов, он сам пытается преобразовать информацию. В данном случае он преобразовал строку '7' в число 7, а потом сложил 1 и 7.
Слабая типизация
Не все языки так делают. PHP — это язык со слабой типизацией. Он знает о существовании разных типов (числа, строки и другие), но относится к их использованию не строго и пытается преобразовывать данные, когда это кажется ему разумным.
Обратите внимание: оператор + в PHP всегда означает арифметику, а для соединения строк есть отдельный оператор — конкатенация .. Поэтому в выражении 1 + '7' PHP превращает строку в число, а в выражении 1 . '7' — наоборот, число в строку:
<?php
print_r(1 + '7'); // => 8
print_r(1 . '7'); // => 171 + '7' → 8 (строка превратилась в число, сложение)
'7' - 1 → 6 (строка превратилась в число, вычитание)
1 . '7' → '17' (число превратилось в строку, конкатенация)Граница дозволенного у PHP все же есть. Если строку никак нельзя понять как число, современный PHP остановит программу с ошибкой:
<?php
print_r(1 + 'seven');
// TypeError: Unsupported operand types: int + stringНо стоит строке начинаться с цифры — и PHP снова попробует «угадать»: выражение 1 + '7 самураев' вернет 8, лишь выдав предупреждение.
А как в строгих языках?
В языках со строгой (сильной) типизацией сложить число со строкой не получится — программа остановится с ошибкой. Например, в Python или Ruby выражение 1 + '7' приведет к ошибке типов: язык требует, чтобы программист явно указал, как преобразовать данные.
При этом языки не делятся ровно на два лагеря — «строгие» и «слабые». Корректнее говорить, что у разных языков разная степень строгости: где-то неявных преобразований почти нет, а где-то их много. PHP находится у «слабого» края этой шкалы, хотя с каждой новой версией становится строже.
Статическая и динамическая типизация
Есть и другое, отдельное понятие — статическая и динамическая типизация. Оно описывает, когда проверяются типы. PHP относится к динамически типизированным языкам: типы проверяются во время работы программы. В статически типизированных языках проверка обычно происходит раньше, еще до запуска кода, на стадии компиляции.
Важно не путать две вещи:
- статическая/динамическая типизация отвечает на вопрос «когда проверяются типы»;
- сильная/слабая типизация отвечает на вопрос «что произойдет, если смешать разные типы без явного преобразования».
Это независимые свойства. PHP — язык динамический и слабо типизированный.
Почему PHP такой
PHP был создан для интернета, а в интернете вся информация — это строки. Даже когда мы вводим на сайте номер телефона или год рождения, на сервер эта информация поступает не как числа, а как строки. Поэтому авторы языка решили, что автоматически преобразовывать типы — правильно и удобно.
Удобство есть, но у него высокая цена. На практике неявные преобразования создают множество ошибок и проблем, которые трудно найти: код может иногда работать, а иногда не работать. Это зависит от того, «повезло» ли в конкретном случае с автоматическим преобразованием. Программист замечает это не сразу.
В дальнейших заданиях мы будем встречаться с таким поведением не раз. Часто будет возникать вопрос «почему мой код работает не так, как я ожидаю?». Слабая типизация красной нитью проходит сквозь всю разработку на PHP. Чуть позже в этом модуле мы научимся преобразовывать типы явно — и делать это всегда осознанно.
Задание
В игре два игрока. Первый набрал 7 очков, второй потерял очки: выражение (-8 - -2) описывает его результат. Посчитайте разницу и выведите на экран: 7 - (-8 - -2).
Попробуйте сделать число 7 не числом, а строкой: '7' - (-8 - -2). Сработает ли такой код? Поэкспериментируйте с другими числами тоже.
Полезное
PHP: Слабая типизация
Нам известно про два разных типа данных: числа и строки. Мы могли складывать числа, потому что операция сложения — это операция для типа «числа». А что, если применить эту операцию к числу и строке?
<?php
print_r(1 + '7'); // => 8'7' — это строка, а не число, при этом интерпретатор PHP выдал ответ 8, как если бы мы складывали два числа. Когда PHP видит несоответствие типов, он сам пытается преобразовать информацию. В данном случае он преобразовал строку '7' в число 7, а потом сложил 1 и 7.
Слабая типизация
Не все языки так делают. PHP — это язык со слабой типизацией. Он знает о существовании разных типов (числа, строки и другие), но относится к их использованию не строго и пытается преобразовывать данные, когда это кажется ему разумным.
Обратите внимание: оператор + в PHP всегда означает арифметику, а для соединения строк есть отдельный оператор — конкатенация .. Поэтому в выражении 1 + '7' PHP превращает строку в число, а в выражении 1 . '7' — наоборот, число в строку:
<?php
print_r(1 + '7'); // => 8
print_r(1 . '7'); // => 171 + '7' → 8 (строка превратилась в число, сложение)
'7' - 1 → 6 (строка превратилась в число, вычитание)
1 . '7' → '17' (число превратилось в строку, конкатенация)Граница дозволенного у PHP все же есть. Если строку никак нельзя понять как число, современный PHP остановит программу с ошибкой:
<?php
print_r(1 + 'seven');
// TypeError: Unsupported operand types: int + stringНо стоит строке начинаться с цифры — и PHP снова попробует «угадать»: выражение 1 + '7 самураев' вернет 8, лишь выдав предупреждение.
А как в строгих языках?
В языках со строгой (сильной) типизацией сложить число со строкой не получится — программа остановится с ошибкой. Например, в Python или Ruby выражение 1 + '7' приведет к ошибке типов: язык требует, чтобы программист явно указал, как преобразовать данные.
При этом языки не делятся ровно на два лагеря — «строгие» и «слабые». Корректнее говорить, что у разных языков разная степень строгости: где-то неявных преобразований почти нет, а где-то их много. PHP находится у «слабого» края этой шкалы, хотя с каждой новой версией становится строже.
Статическая и динамическая типизация
Есть и другое, отдельное понятие — статическая и динамическая типизация. Оно описывает, когда проверяются типы. PHP относится к динамически типизированным языкам: типы проверяются во время работы программы. В статически типизированных языках проверка обычно происходит раньше, еще до запуска кода, на стадии компиляции.
Важно не путать две вещи:
- статическая/динамическая типизация отвечает на вопрос «когда проверяются типы»;
- сильная/слабая типизация отвечает на вопрос «что произойдет, если смешать разные типы без явного преобразования».
Это независимые свойства. PHP — язык динамический и слабо типизированный.
Почему PHP такой
PHP был создан для интернета, а в интернете вся информация — это строки. Даже когда мы вводим на сайте номер телефона или год рождения, на сервер эта информация поступает не как числа, а как строки. Поэтому авторы языка решили, что автоматически преобразовывать типы — правильно и удобно.
Удобство есть, но у него высокая цена. На практике неявные преобразования создают множество ошибок и проблем, которые трудно найти: код может иногда работать, а иногда не работать. Это зависит от того, «повезло» ли в конкретном случае с автоматическим преобразованием. Программист замечает это не сразу.
В дальнейших заданиях мы будем встречаться с таким поведением не раз. Часто будет возникать вопрос «почему мой код работает не так, как я ожидаю?». Слабая типизация красной нитью проходит сквозь всю разработку на PHP. Чуть позже в этом модуле мы научимся преобразовывать типы явно — и делать это всегда осознанно.
Задание
В игре два игрока. Первый набрал 7 очков, второй потерял очки: выражение (-8 - -2) описывает его результат. Посчитайте разницу и выведите на экран: 7 - (-8 - -2).
Попробуйте сделать число 7 не числом, а строкой: '7' - (-8 - -2). Сработает ли такой код? Поэкспериментируйте с другими числами тоже.
Полезное
Ваше упражнение проверяется по этим тестам
<?php
namespace HexletBasics\DataTypes\WeakTyping;
use HexletBasics\Exercise\TestCase;
class SolutionTest extends TestCase
{
public function test()
{
$expected = '13';
$this->assertOutput($expected);
}
}Решение учителя откроется через:
20:00
