Какая система типов используется в php
В PHP используется система номинальных типов с сильным поведенческим отношением подтипизации. Отношение подтипизации проверяется во время компиляции, в то время как верификация типов проверяется динамически во время выполнения.
Система типов PHP поддерживает различные атомарные типы, которые могут быть объединены вместе для создания более сложных типов. Некоторые из этих типов могут быть записаны как объявление типов.
Атомарные типы
Некоторые атомарные типы являются встроенными типами, которые тесно интегрированы с языком и не могут быть воспроизведены с помощью типов, определённых пользователем.
- Встроенные типы
- Тип null
- Скалярные типы:
- Тип bool
- Тип int
- Тип float
- Тип string
- false
- true
- Интерфейсы
- Классы
- Перечисления
Составные типы
Возможно объединение нескольких атомарных типов в составные типы. PHP позволяет объединять типы следующими способами:
- Пересечение классов-типов (интерфейсов и имён классов).
- Объединение типов.
Пересечение типов
Пересечение типов принимает значения, удовлетворяющие не одному, а нескольким объявлениям типов классов. Отдельные типы, образующие пересечение типов, соединяются символом & . Поэтому пересечение типов, состоящее из типов T , U и V , будет записано как T&U&V .
Объединение типов
Объединение типов принимает значения нескольких различных типов, а не одного. Отдельные типы, образующие объединение типов, соединяются символом | . Поэтому объединение типов, состоящее из типов T , U и V , будет записано как T|U|V . Если один из типов является пересечением типов, то для записи в DNF его нужно заключить в скобки: T|(X&Y) .
Псевдонимы типов
PHP поддерживает два псевдонима типов: mixed и iterable , которые соответствуют объединению типов object|resource|array|string|float|int|bool|null и Traversable|array соответственно.
Замечание: PHP не поддерживает определяемые пользователем псевдонимы типов.
User Contributed Notes
There are no user contributed notes for this page.
- Типы
- Введение
- Система типов
- NULL
- Логический тип
- Целые числа
- Числа с плавающей точкой
- Строки
- Числовые строки
- Массивы
- Объекты
- Перечисления
- Ресурс
- Функции обратного вызова (callback-функции)
- Mixed
- Void
- Never
- Относительные типы классов
- Value types
- Итерируемые
- Объявление типов
- Манипуляции с типами
- Copyright © 2001-2023 The PHP Group
- My PHP.net
- Contact
- Other PHP.net sites
- Privacy policy
Какая система типов используется в php
PHP является языком с динамической типизацией. Это значит, что тип данных переменной выводится во время выполнения, и в отличии от ряда других языков программирования в PHP не надо указывать перед переменной тип данных.
В PHP есть десять базовых типов данных:
- bool (логический тип)
- int (целые числа)
- float (дробные числа)
- string (строки)
- array (массивы)
- object (объекты)
- callable (функции)
- mixed (любой тип)
- resource (ресурсы)
- null (отсутствие значения)
Из этих типов данных первые четыре являются скалярными: bool, int, float, string . Поэтому вначале именно их и рассмотрим.
int (целочисленный тип)
Представляет целое число со знаком.
$num = -100; echo $num;
Здесь переменная $num представляет целочисленный тип, так как ей присваивается целочисленное значение.
Кроме десятичных целых чисел PHP обладает возможностью использовать также двоичные, восьмеричные и шестнадцатеричные числа. Шаблоны чисел для других систем:
- шестнадцатеричные : 0[xX][0-9a-fA-F]
- восьмеричные : 0[0-7]
- двоичные : 0b[01]
"; echo "num_2 = $num_2
"; echo "num_8 = $num_8
"; echo "num_16 = $num_16"; ?>Переменная типа int занимает в памяти 32 бита, то есть может принимаь значения от -2 147 483 648 до 2 147 483 647. Если переменная получает числовое значение вне этого диапазона, то она трактуется как переменная типа float
Тип float (числа с плавающей точкой)
Размер числа с плавающей точкой зависит от платформы. Максимально возможное значение, как правило, составляет 1.8*10 308 с точностью около 14 десятичных цифр. Например:
Тип bool (логический тип)
Переменные логического типа могут принимать два значения: true и false или иначе говоря истина и ложь . Чаще всего логические значения используются в условных конструкциях:
Тип string (строки)
Для работы с текстом можно применять строки. Строки бывают двух типов: в двойных кавычках и одинарных. От типа кавычек зависит обработка строк интерпретатором. Так, переменные в двойных кавычках заменяются значениями, а переменные в одинарных кавычках остаются неизменными.
"; echo $result; $result = '$a+$b'; echo $result; ?>
В этом случае мы получим следующий вывод:
10+5 $a+$b
Кроме обычных символов, строка может содержать специальные символы, которые могут быть неправильно интерпретированы. Например, нам надо добавить в строку кавычку:
$text = "Модель "Apple II"";
Данная запись будет ошибочна. Чтобы исправить ошибку, мы можем сочетать различные типы кавычек (‘Модель «Apple II»‘ или «Модель ‘Apple III'») или использовать слеш, чтобы ввести кавычку в строку:
$text = "Модель \"Apple II\"";
Специальное значение null
Значение null указывает, переменная не имеет значения. Использование данного значения полезно в тех случаях, когда мы хотим указать, что переменная не имеет значения. Например, если мы просто определим переменную без ее инициализации, и затем попробуем ее использовать, то нам интерпретатор выдаст сообщение, что переменная не установлена:
Использование значения null поможет избежать данной ситуации. Кроме того, мы сможем проверять наличие значения и в зависимости от результатов проверки производить те или иные действия:
Константа null не чувствительна к регистру, поэтому мы можем написать и так:
$a = NULL;
Динамическая типизация
Поскольку PHP — язык с динамической типизацией, то мы можем присваивать одной и той же переменной значения разных типов:
id = $id"; $id = "jhveruuyeru"; echo "
id = $id
"; ?>Достоинства и фатальные недостатки типизации в php
Язык php часто ругают, обычно необоснованно. Особенно удивляет, что javascript ругают меньше. Зачастую это делают люди, которые писали на нем 10+ лет назад, когда язык был действительно чертовски плох, да и разработчики в те времена не задумывались над качеством кода. Посмотрите хотя бы на код wordpress, который до сих пор вызывает шок.
Ругают необоснованно, но проблемы у языка, конечно же, есть, и они серьёзные. Разуметеся, если сравнить последние релизы php7 (с нормальным ООП и строгим тайпхинтингом) и php4, то разница будет колоссальная. Однако и в последних версиях языка не всё гладко, и до java/c# пока что очень далеко. Более того, берусь утверждать, что будущее php тоже довольно сомнительно (с точки зрения типов).
Другими словами, давайте рассмотрим предметно, что хорошо и что плохо в php с точки зрения типизации.
Тайп хинтинги
Для начала давайте разберемся, для чего вообще нужны тайпхинтинги в php, чтобы ни у кого не осталось вопросов а ля «зачем эта лишняя писанина».
Немного отвлечемся и посмотрим кусок кода на javascript:
function filterUsersByAge(users, age) < // тут какой-то код >Что мы можем сказать об этой функции? Она берет каких-то пользователей и фильтрует их по возрасту. Но этого мало, потому что сразу возникают вопросы:
Что такое users? Массив? Или какой-то хитрый объект-коллекция?
Возраст задан как целое число или может быть дробным?
Может ли возраст быть null?
Возвращает ли эта фунция значение или же меняет переданный массив users?Чтобы всё это понять, надо прочесть код функции, а также вызовы этой функции. Ошибки будет отловить сложно, потому что язык не будет ругаться ни на какие аргументы, а будет пытаться их как-то привести к нужному типу.
Как известно, программист тратит больше времени на чтение и понимание кода, чем на написание нового, поэтому отстутствие подсказок в коде является затармаживающим фактором.
Для сравнения код на последних версиях php:
function filterUsersByAge(array $users, ?int $age) : array < // . >Тут мы видим, что на входе массив пользователей, возраст может быть null, возвращается также массив. Гораздо яснее, не так ли? Если же в нужных местах указать declare(strict_types=1) , то при попытке пихнуть дробное число в качестве возраста, мы получим ошибку.
Вроде всё супер, но есть нюансы.
Нет дженериков
Мы смотрим на эту php-функцию filterUsersByAge и сходу не понимаем, массив чего нам пришел. Что именно за array? В java можно было бы написать List , и мы бы понимали, что к нам пришел список объектов User. Или Set , и мы бы сразу видели, что это список без повторов, т.е. только разные объекты. (Вообще, array в php — это странноватая смесь массива и HashMap, но это тема для отдельной статьи)
Нет уточнений для типа callable.
Вот пример функции:
function reduce ( array $array, callable $callback )Что за функция идет вторым аргументом? Что в ней должно быть?
Только в комментариях к коду мы можем понять, что там должно быть, к примеру, два аргумента. Кстати, есть четыре вида лжи: ложь, наглая ложь, статистика и комментарии к коду.
В некоторых языках, например в TypeScript, можно прописать прямо в объявлении функции:
function fn(action: (a: string, b: number) => void)Т.е. здесь в качестве аргумента action должна быть функция с двумя аргументами (строка и число), которая ничего не возрващает. Всё максимально явно, IDE и компилятор сразу скажут, если аргумент был какой-то не такой
Странности тайпхинтинга и типа возврата в связке с наследованием
class User implements Entity <> abstract class Repository < abstract public function findById(): Entity; >class UserRepository extends Repository < function findById(): User < return new User(); >>Здесь получаем ошибку, что findById не совместим с findById из абстрактного класса.
Такой же пример в java нормально компилируется:
interface Entity <> class User implements Entity <>; abstract class Repository < abstract public Entity findById(); >class UserRepository extends Repository < public User findById()< return new User(); >>в TypeScript тоже можно:
interface Entity <> class User implements Entity <> abstract class Repository < public abstract findById(): Entity; >class UserRepository extends Repository < public findById(): User< return new User(); >>На это дело время от времени появляются баг репорты, возможно будет исправлено когда-нибудь:
- https://bugs.php.net/bug.php?id=75823
- https://bugs.php.net/bug.php?id=71825
Фатальная проблема
Самая большая проблема в том, что php проверяет типы во время выполнения, а не во время компиляции. Потому что, не смотря на strict_types и type hintings, это ВНЕЗАПНО не строго типизированный язык
Отсюда следует два вывода:
1) Чем больше проверок в рантайме, тем больше тормозов. Поэтому слишком сложные проверки навряд ли вообще когда-нибудь появятся. Многослойные дженерики и callable с callable аргументами просто положат рантайм. Также будут тормозить рантайм введение типов для членов класса и в других местах.
2) Ошибки выявляются только во время запуска. Т.е. всегда будут ситуации, когда в какой-то хитрой ситуации пользователь сделает что-то не предусмотренное тестами, и всё повалится
Вместо выводов
Хотя (с точки зрения типов и ООП) на мой взгляд php на голову выше, чем javascript, и подходит для написания сложных программ, но при этом, конечно, не дотягивает до java/c#/typescript, и навряд ли когда-нибудь дотянется (см «Фатальная проблема»). Повторюсь, не дотянется именно с точки зрения системы типов, в остальных вещах возможны предпочтения в ту или иную сторону.
Поэтому в по-настоящему сложных приложениях надо обязательно всё обкладывать тестами. Также, возможно, что phpdoc добавит поддержку сложных callable с параметрами, и IDE научатся их понимать.
Несколько слов о типизации в PHP
Теги: php, clang, типизация, dynamic typing, static typing, compile-time, run-time, integer, strong typing, weak typing, _zval_struct, zvalue_value, zend_value, динамическая типизация, статическая типизация

По виду типизации, языки программирования делятся на языки с динамической (dynamic typing) и статической типизацей (static typing). Статическая типизация — когда тип переменной точно известен в compile-time, например в Clang int a = 1; и в run-time тип переменной «a» может быть только integer.
С динамической типизацией попроще. Тип переменной выводится в run-time, например, в PHP $a = 1; и в run-time переменная «$a» может быть числом 1 или даже строкой «string». Тип переменной обуславливает операции, которые мы можем с ней производить, например, числа – складывать, а в строках искать вхождение подстроки.
Типизация, в свою очередь, делится на сильную (strong typing) и слабую (weak typing). Когда мы выполняем какую-либо операцию при сильной типизации, то два операнда должны иметь один и тот же тип, например в Python 1 + “string” вызовет ошибку, потому что 1 – число, а «string» – строка.
А вот в языках со слабой типизацией ошибки не будет, например в PHP 1 + “string” вернёт цифру 1. И причиной всему является приведение типов. Интерпретатор PHP начинает парсить строку «string», чтобы привести её к числу. Напарсить ничего стоящего у него не получается и он приводит строку «string» к цифре 0, которое в итоге и прибавляется к цифре 1. Строку «42string» интерпретатор приведёт к числу 42, а если надо привести строку «47.4string» к числу с плавающей точкой, то мы получим 47.4.
Таким образом, PHP – это язык со слабой динамической типизацией. Информация о выведенном типе переменной хранится в структуре «_zval_struct», в этой же структуре хранится ссылка на union-структуру zvalue_value (zend_value в PHP7), где и хранится реальное значение, на которое и указывает переменная.
Знание того, как устроен и работает zend_value помогает ответить на такие вопросы, как, например, «А какой тип будет у переменной «$a», которая ссылается на самое большое число (константа PHP_INT_MAX), если её сложить саму с собой (тип intger поменяется на double)?».
