Как включить строгую типизацию в PHP и для чего ее использовать
PHP исторически не был языком со строгой типизацией. Разработчики использовали переменные, в которые могли поместить практически что угодно. При этом во время своего развития PHP получал все больше и больше ограничений, связанных с типами.
Подсказки, которые в параметрах метода или свойствах класса указывают разработчику на тип данных, при правильном использовании бывают очень полезны. Они могут выявлять ошибки перед запуском кода и делают жизнь программистов легче. Вообще, объявление типа для класса появляется в языке только с версии PHP 5.
Обычно при передаче в функцию неожиданного типа PHP попытается автоматически привести значение к ожидаемому типу. Если была включена строгая типизация с помощью strict_types=1 , PHP вместо приведения к другому типу данных просто выдаст исключение.
То есть использование declare(strict_types=1) сообщит PHP, что нужно выдавать TypeError , когда вы пытаетесь преобразовать примитивные значения.
Например, как работает PHP без включенной строгой типизации:
function dump(int $value): void var_dump($value); > dump('13.37'); dump(19.42);
Запуск этого кода приведет к следующему результату:
int(13) int(19)
Функция dump из примера ожидает, что ей передадут целые числа. И хотя мы в одном из вызовов передаем ей строку, PHP самостоятельно преобразует ее в целое число и выдает результат. Конечно, IDE, которое использует программист, скорее всего предупредит о преобразовании данных, но тем не менее результат остается действующим PHP-кодом.
Как включить строгие типы
Включить строгую типизацию для примитивных значений очень просто — для этого нужно добавить команду declare(strict_types=1) в самое начало файла:
declare(strict_types=1) function dump(int $value): void var_dump($value); > dump('13.37'); dump(19.42);
Запуск такого кода с объявлением о строгой типизации приведет к ошибке.
Fatal error: Uncaught TypeError: dump(): Argument #1 ($value) must be of type int, string given, called in /Users/rienvanvelzen/Desktop/demo.php on line 10 and defined in /Users/rienvanvelzen/Desktop/demo.php:5 Stack trace: #0 /Users/rienvanvelzen/Desktop/demo.php(10): dump('13.37') #1 thrown in /Users/rienvanvelzen/Desktop/demo.php on line 5
Использование strict_type поможет разработчику выявить ошибки еще на ранней стадии, ограничивая PHP для автоматического переопределения примитивных типов данных.
Маленькое предостережение
Есть одна важная вещь в работе strict_type , которую нужно обязательно учитывать. Запрет на переопределение примитивных типов работает только в файле, где используется это объявление. Это означает, что когда разработчик в другом файле использует класс, который где-то у себя имеет объявление strict_type , это не спасет от переопределения примитивных данных в этом PHP-файле.
То есть строгая типизация применяется к вызовам функций, сделанным изнутри файла с включенной строгой типизацией, а не к функциям, объявленным в этом файле.
Эта статья является переводом материала «The way declare(strict_types=1) works in PHP» разработчика Marinus van Velzen в издании Dev.to.
Какая типизация в php
While waiting for native support for typed arrays, here are a couple of alternative ways to ensure strong typing of arrays by abusing variadic functions. The performance of these methods is a mystery to the writer and so the responsibility of benchmarking them falls unto the reader.
PHP 5.6 added the splat operator (. ) which is used to unpack arrays to be used as function arguments. PHP 7.0 added scalar type hints. Latter versions of PHP have further improved the type system. With these additions and improvements, it is possible to have a decent support for typed arrays.
declare ( strict_types = 1 );
function typeArrayNullInt (? int . $arg ): void >
function doSomething (array $ints ): void (function (? int . $arg ) <>)(. $ints );
// Alternatively,
(fn (? int . $arg ) => $arg )(. $ints );
// Or to avoid cluttering memory with too many closures
typeArrayNullInt (. $ints );
function doSomethingElse (? int . $ints ): void /* . */
>
$ints = [ 1 , 2 , 3 , 4 , null ];
doSomething ( $ints );
doSomethingElse (. $ints );
?>
Both methods work with all type declarations. The key idea here is to have the functions throw a runtime error if they encounter a typing violation. The typing method used in doSomethingElse is cleaner of the two but it disallows having any other parameters after the variadic parameter. It also requires the call site to be aware of this typing implementation and unpack the array. The method used in doSomething is messier but it does not require the call site to be aware of the typing method as the unpacking is performed within the function. It is also less ambiguous as the doSomethingElse would also accept n individual parameters where as doSomething only accepts an array. doSomething’s method is also easier to strip away if native typed array support is ever added to PHP. Both of these methods only work for input parameters. An array return value type check would need to take place at the call site.
If strict_types is not enabled, it may be desirable to return the coerced scalar values from the type check function (e.g. floats and strings become integers) to ensure proper typing.
2 years ago
The documentation lacks the information, that it’s possible to change the return type of a method defined in an interface when the interface’s methods return type is defined as `mixed`.
«The mixed return type could be narrowed in a subclass as this is covariant and is allowed in LSP.» (https://wiki.php.net/rfc/mixed_type_v2)
This means the following code is valid in PHP 8.0:
interface ITest
public function apfel (): mixed ; // valid as of 8.0
>
class Test implements ITest
public function apfel (): array // more explicit
return [];
>
>
var_dump ((new Test ())-> apfel ());
?>
You can see the result here: https://3v4l.org/PXDB6
2 years ago
same data type and same value but first function declare as a argument type declaration and return int(7)
and second fucntion declare as a return type declaration but return int(8).
function argument_type_declaration(int $a, int $b) return $a+$b;
>
function return_type_declaration($a,$b) :int return $a+$b;
>
2 years ago
Not explicit is that function parameters can also have union type declarations; they’re not just for property and return value declarations.
declare( strict_types = 1 );
function foo ( int | string $arg )
if( is_string ( $arg ))
echo «It’s a string!\n» ;
>
elseif( is_int ( $arg ))
echo «It’s an integer!\n» ;
>
else
echo «It shouldn’t be here!\n» ;
>
>
foo ( 42 );
foo ( ‘bar’ );
foo ([]);
2 years ago
function a ( bool $a , bool $b ) return $a + $b ;
>
var_dump ( a ( false , 3.9 ));
?>
Output
——
int(1)
- Типы
- Введение
- Система типов
- 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 в ряде ситуаций — при определении свойств классов, параметров или возвращаемого значения функций — позволяет указать тип данных. Установка типа данных позволит избежать ситуаций, когда в программу будут переданы данные не тех типов, которые ожидалась разработчиком.
function isPositive($number) < return $number >0; > $result = isPositive("-Youdontknowwhoiam"); if($result) echo "положительное"; else echo "отрицательное или равно нулю";В данном случае функция isPositive() очевидно ожидает, что в качестве параметра будет передано число, чтобы установить, больше оно нуля или нет. Тем не менее при вызове функции мы можем передать в нее произвольное значение. Чтобы оградиться от подобным ситуаций необходимо явным образом указать, что функция может принимать только число, то есть типизировать параметр функции.
Определение типа
Какие определения типов могут использоваться при типизации:
- bool : допустимые значения true и false
- float : значение должно число с плавающей точкой
- int : значение должно представлять целое число
- string : значение должно представлять строку
- mixed : любое значение
- callable : значение должно представлять функцию
- array : значение должно представлять массив
- iterable : значение должно представлять массив или класс, который реализует интерфейс Traversable . Применяется при переборе в цикле foreach
- Имя класса: объект должен представлять данный класс или его производные классы
- Имя интерфейса: объект должен представлять класс, который реализует данный интерфейс
- Self : объект должен представлять тот же класс или его производный класс. Может использоваться только внутри класса.
- parent : объект должен представлять родительский класс данного класса. Может использоваться только внутри класса.
Типизация параметров функции
При типизации параметров тип указывается перед названием параметра:
function isPositive(int $number) < return $number >0; > $result1 = isPositive(25); // норм - 25 число $result2 = isPositive("25"); // норм - PHP может преобразовать значение в число $result3 = isPositive("-Youdontknowwhoiam"); // Ошибка TypeErrorВ данном случае параметр $number должен представлять тип int , то есть целое число. Поэтому при вызове функции мы должны передать в функцию целочисленное значение. Если будет передано значение другого типа, то PHP попытается преобразовать значение. В некоторых случаях такое преобразование можно завершится успешно:
$result2 = isPositive("25");В других случаях прееобразование может завершится неудачно, и программа завершит выполнение с ошибкой TypeError :
$result3 = isPositive("-Youdontknowwhoiam");function sum(array $numbers, callable $condition) < $result = 0; foreach($numbers as $number)< if($condition($number)) < $result += $number; >> return $result; > $isPositive = function($n) < return $n >0;>; $myNumbers = [-2, -1, 0, 1, 2, 3, 4, 5]; $positiveSum = sum($myNumbers, $isPositive); echo $positiveSum; // 15
В данном случае параметры функции должный представлять массив и другую функцию (тип callable ). В качестве функции можно передать анонимную функцию.
Типизация возвращаемого значения
Для установки типа возвращаемого из функции значения после списка параметров указывается двоеточие : и после него тип данных:
function isPositive (int $number) : bool < return $number >0; > $result = isPositive(34);
В данном случае функция isPositive должна возвращать значение типа bool , то есть true или false .
Другой пример — возвращение функции:
function select($n): callable< switch($n)< case 1: return function($a, $b) ; case 2: return function($a, $b) ; case 3: return function($a, $b) ; default: return function($a, $b) ; > > $selection = select(2); echo $selection(4,5); // -1
Особо стоит отметить ключевое слово static , добавленное в PHP 8, которое применяется, если надо возвратить из метода класса объект этого же класса:
class Node < function generate() : static< return new Node(); >> $node1 = new Node(); $node2 = $node1->generate();
Типизация свойств
В качестве типа свойств может применяться любой тип кроме callable :
class Person < public $name; public int $age; >$tom = new Person(); $tom->name = "Tom"; $tom->age = 36; // корректное значение echo $tom->age; // 36 $tom->age = "36"; // корректное значение, так как PHP может преобразовать в число echo $tom->age; // 36 $tom->age = "thirty-eight"; // некорректное значение, возникнет ошибка TypeError echo $tom->age;
В данном случае явным образом определено, что свойство $age представляет именно тип int , то есть целое число. Соответственно этому свойству мы сможем присвоить только целое число.
Стоит учитывать, что свойство, для которого не указан тип данных, по умолчанию имеет значение null . Тогда как свойство, для которого указан тип, неинициализировано, то есть не имеет никакого конкретного значения.
class Person < public $name; // равно null public int $age; // неинициализировано >
Соответственно если нетипизированное свойство мы сможем использовать, то при попытке обратиться к типизированному, но неинициализиованному свойству программа завершит выполнение ошибкой:
$tom = new Person(); echo $tom->name; // норм - null echo $tom->age; // ошибка - свойство неинициализировано
Тип Union
В PHP 8 был добавлен тип union или объединение, который по сути представляет объединение типов, разделенных вертикальной чертой | . Например, мы хотим написать функцию сложения чисел, и чтобы в функцию можно было передавать только числа. Однако числа в PHP предствлены двумя типами — int и float . Чтобы не создавать по функции для каждого типа, применим объединения:
function sum(int|float $n1, int|float $n2,): int|float < return $n1 + $n2; >echo sum(4, 5); // 9 echo "
"; echo sum(2.5, 3.7); // 6.2В данном случае мы говорим, что параметры $n1 и $n2 могут представлять как тип int , так и тип float . Аналогично возвращаемое значение также может представлять либо int , либо float .
Пишем на php… статично
PHP- это язык с динамической неявной слабой типизацией. Динамическая типизация бывает очень полезна во многих случаях, да и вообще сильно упрощает жизнь, ведь ты концентрируешься на значениях и не задумываешься о том какого они типа.
Я как и многие php программисты думал что статическая типизация это «усложнение». Она ограничивает гибкость и вообще: как люди с ней работают? И искренне не понимал, почему многие опытные программисты отдают предпочтение языкам со статической типизацией и строгой проверкой типов.

Я относился к правой половине людей, которые мало что знают о типах, но при этом искренне верят, что это не удобно. И так было до тех пор пока я не познакомился с одним из строго типизированных языков (c#) вплотную. С тех пор мое отношение к php да и вообще к программированию в целом изменилось.
«Титанов» программирования эта статья вряд ли заинтересует, потому что здесь вы не найдете ничего революционного и нового, а остальным заинтересованным в улучшении своего кода и собственной производительности добро пожаловать под кат.
Для начала определимся вообще что такое статическая типизация:
Статическая типизация определяется тем, что конечные типы переменных и функций устанавливаются на этапе компиляции. Т.е. уже компилятор на 100% уверен, какой тип где находится.
В php у нас нет компилятора, и все типы в любом случае будут вычисляться на этапе выполнения, но это не мешает нам самим строго следить за ними, придерживаясь определенных правил.
Для чего все это нужно в PHP?
Изучая c# и параллельно осваивая продукт, по которому ставились задачи, не имея достаточного опыта и документации (точнее документации не было вообще), меня выручало то, что благодаря строгой типизации большинство ошибок отсеивалось сразу, а еще большим плюсом были подсказки IDE, выдаваемые на основе заданных типов. Мне не нужна была документация, что бы понять что и куда передавать, я не мог сделать что то не так, оно просто не компилировалось!
Это заметно сокращало время, потому что ты сразу видишь, что этот метод, принимает только такие параметры, а создавая объекты для данных параметров, узнаешь, каких звеньев не хватает для их конструирования и так далее.
“Хорошо, это и вправду удобно” — скажете вы — “Но ты не рассказал нам ничего нового, в PHP есть PHPDoc, который понимает большинство современных IDE, и помогает так же “на лету” писать код!”
Все верно, но что бы это работало так же как в статично типизированных языках необходимо не просто написать комментарий у каждого метода и свойства класса, но важно что бы вся архитектура была заточена под работу с заранее известными объектами. Что бы построить такую архитектуру, нужно придерживаться определенных правил. Именно о них я бы хотел поговорить далее.
Используйте объекты вместо массивов
Да, именно так. Во общем эта истина не нова и о ней написано много: объекты проще расширить, к ним проще добавить методы, и вообще, дорогу ООП.
Но я хочу рассмотреть этот вопрос с другой стороны — с точки зрения построения правильной архитектуры для эффективного программирования.
Рассмотрим простой пример:
Скажем, в системе происходит событие, и нам необходимо передать в обработчик некие параметры.
Используем для этого массив:$eventData = array( 'sender' => $controller, //экземпляр некоего контроллера 'name' => 'onDelete', 'group' => 'global', 'arguments' => array( 'id' => 15 ), ); $eventDispatcher->triggerEvent($eventData); . /** * Обработчик события удаления * @param array $eventData */ protected function onDelete($eventData) < //Здесь к нам в $eventData попадает некий массив, //структуру которого мы сможем узнать только вызвав var_dump() //или же найдя код где это событие вызывается $model = $eventData['sender']->model->deleteChilds(); >Простейший и довольно частый случай, ничего сложного, составляем массив с данными и отправляем его в функцию.
А теперь представим, что вызов этого события находится где-то глубоко в недрах написанной не вами (или вами, но не вчера) программы.
Представили? И хорошо, если есть документация, в которой описан формат этого массива — значит вам не придется тратить время на поиски вызывающего участка кода, дабы подсмотреть структуру массива. Либо же вы воспользуетесь var_dump(), и все равно потратите время, что бы понять, что там происходит.
Давайте теперь рассмотрим что будет, если вместо массива мы описали бы класс и создали его объект. Изменим код:
class EventData < /** * Экземпляр контроллера, инициировавший событие * @var BaseController */ public $sender; /** * Имя события * @var string */ public $name; /** * Группа к которой относится событие (нэймспейс) * @var string */ public $group; /** * Массив с произвольными аргументами * @var array */ public $arguments; >$eventData = new EventData(); $eventData->sender = $controller; $eventData->name = 'onDelete'; $eventData->group = 'global'; $eventData->arguments = array('id' => 15); $eventDispatcher->triggerEvent($eventData); . /** * Обработчик события удаления * @param EventData $eventData */ protected function onDelete($eventData) < $eventData->sender->model->deleteChilds(); >Что мы получили в итоге? Теперь наша любимая IDE подсказывает нам, что же содержит полученный объект.

Кроме того, благодаря тому что мы подробно расписали тип для каждого атрибута в переданном объекте, мы можем тут же получить подсказки и по ним. Т.е. набрав $eventData->controller-> — мы можем увидеть, что находится внутри атрибута с именем controller.
Теперь вам не придется лезть куда-то в дебри кода, для того что бы понять, что же передается в этом объекте и какого оно типа. Представьте, как вам будут благодарны другие программисты, которые будут работать с вашим кодом!
Если в вашем приложении активно используется ActiveRecord паттерн, то вы уже близки к тотальной типизации, но если вы до сих пор получаете элементы из базы данных в виде массивов, и гоняете их туда сюда, много раз от функции к функции, то стоит задуматься о смене архитектуры.
Это был простой и довольно синтетический пример. Возможно в вашем проекте в похожей ситуации и так используется объект, а не массив. Но посмотрите внимательнее, бывают ситуации не похожие на эту, например, в какую-либо функцию передаются трехэтажные массивы, или же функция имеет десяток аргументов непонятного типа.
Продолжая улучшать наш пример, я бы не остановился на создании одного класса. Обычно в современных веб-приложениях происходит много различных событий, и в них передаются разные аргументы, их можно сгруппировать, и для каждой группы событий создать свой — подходящий класс аргументов.
Не бойтесь создавать классы. Вам не обязательно создавать для каждого отдельный файл, если они взаимосвязаны друг с другом.
Например, я бы создал файл EventArguments.php, и в нём бы описал все возможные варианты аргументов событий.UPD: Я не призываю понимать мой призыв заменить ВСЕ массивы на объекты буквально, это не правильно.
Массив — упорядоченный набор данных, для хранения данных одного типа, идентифицируемых с помощью одного или нескольких индексов.
Именно в таком ключе и должны использоваться массивы. т.е. хранить некие упорядоченные однотипные данные.
Бездумное изменение массивов на объекты может принести больше вреда чем пользы. Поэтому вы должны сами для себя (и для своего проекта) определить грань между удобством использования объектов и производительностью системы.
Инициализируйте переменные с правильным типом.
Сразу к примеру:
/** * Получить детишек * @return array */ public function getChildren()< if(!$this->isLeaf) < return $this->find('where array(':id', $this->id)); > > . foreach($model->getChildren() as $child) < //делаем что либо с потомками >Знакомо? Вся проблема кроется в том, что если условие !$this->isLeaf не выполнится, то результатом функции будет совсем не array, и нам придется писать кучу шаблонного кода, что бы foreach не падал, из-за неправильных аргументов.
Как должно быть:
/** * Получить детишек * @return array */ public function getChildren()< //Во первых необходимо ВСЕГДА определять переменную, прежде чем её использовать - это хороший тон. //Но в нашем случае мы её определяем не абы как, а сразу с тем типом, которым предполагаем использовать. $children = array(); if(!$this->isLeaf) < $children = $this->find('where array(':id', $this->id)); > return $children; >Теперь если условие !$this->isLeaf не выполнится, то результатом функции будет пустой массив который мы определили в начале, и foreach в который попадет значение из этой функции не упадет если что то пойдет не так.
Рассмотренный пример — это лишь вершина айсберга. Если вы всегда будете сразу определять переменную с нужным, заранее известным типом, то вы сможете сэкономить кучу времени. А так же писать более красивый код без дополнительных ухудшающих восприятие кода проверок.
Кстати, это касается не только php. К примеру, в JavaScript в движке V8, определение типа переменной на этапе её создания ускоряет исполнение скрипта, так как не заставляет движок делать лишних преобразований (подробнее в этой статье)
Инструменты строгой типизации.
PHP имеет слабую типизацию, что означает что он не проверяет типы при операциях с ними. Т.е. вы можете сложить строку с числом, или проверить равенство между объектом скаляром, и интерпретатор вам ничего не скажет. Заставить PHP вести себя строго типизировано мы не можем. Однако в своем комплекте PHP имеет несколько удобных (пусть и не всегда логичных) инструментов для контроля типов.
Например, при определении функции вы можете явно указать, какого типа должны быть её параметры:
public function triggerEvent(EventData $event) < //указываем что в эту функцию можно передавать только объекты типа EventData или его потомки >. $dispatcher->triggerEvent(new EventData); //Функция вызовется $dispatcher->triggerEvent(new EventDataChild); //EventDataChild - потомок EventData, функция вызовется $dispatcher->triggerEvent(new AnotherClass()); //Catchable fatal error: Argument 1 passed to EventDispatcher::triggerEvent() must be an instance of EventData, instance of new AnotherClass givenТаким образом, мы без дополнительных проверок оградили себя от случайной передачи в функцию параметра неверного типа. PHP сам проверит тип передаваемого параметра и выдаст ошибку, если он не будет совпадать.
Цитата со страниц мануала о контроле типов php.net/oop5.typehinting:
На данный момент функции имеют возможность заставлять параметры быть либо объектами (путем указания имени класса в прототипе функции), либо интерфейсами, либо массивами (начиная с PHP 5.1), или колбеком с типом callable (начиная с PHP 5.4).
Однако, если NULL использовался как значение параметра по умолчанию, то это будет также допустимо в качестве аргумента для последующего вызова.
Если класс или интерфейс указан для контроля типа, то все его потомки или реализации также допустимы.
Контроль типа не может быть использован со скалярными типами, такими как int или string. Трейты также недопустимы.- SplInt
- SplFloat
- SplEnum
- SplBool
- SplString
Честно признаться, я этим не пользовался, поскольку на мой взгляд это перебор. Кроме того эти классы не входят в стандартную поставку PHP, и распространяются PECL пакетом, что затрудняет их использование.
Используйте PHPDoc везде где это возможно
PHPDoc и его поддержка в IDE — это отличный инструмент, экономящий время PHP программисту.
Поскольку синтаксис языка и его идеология не позволяет установить тип переменной при ее создании, вашей IDE очень сложно понять какая переменная чем является. Так помогите ей — укажите тип в комментарии, и ваша IDE отблагодарит вас подсказками во время работы.
Это еще один этап на пути полной типизации вашего приложения. Если вы будете знать, что получает и что возвращает нужный метод, у вас не возникнет сложностей с его использованием.
Я придерживаюсь следующих правил:
Все публичные атрибуты класса, должны иметь комментарий с описанием типа;
Все публичные методы так же должны иметь описание того, что они делают, и описание каждого параметра, включая то что они возвращают.Небольшие подсказки для тех, кто не знаком достаточно хорошо с PHPDoc (все это корректно для среды NetBeans)
//Если метод возвращает объект некоего класса, // то можно указать имя этого типа в инструкции @return //И тогда IDE при получении результата этой функции будет трактовать его как объект этого класса /** * Этот метод возвращает объект класса EventData * @return EventData */ public function getEventData() < return new EventData(); >//Если метод возвращает массив, содержащий объекты некоего класса, то это можно указать так: //@return EventHandler[] //Ключевой нюанс - это квадратные скобки после имени класса. //Эта конструкция говорит парсеру, что будет возвращен массив, состоящий из объектов этого класса // //Пример: /** Возвращаем массив элементов EventHandler * @return EventHandler[] */ public function getEventHandlers()< return $this->handlers; > public function triggerEvent()< foreach ($this->getEventHandlers() as $handler) < $handler; //на этом этапе IDE будет знать, что $handler является объектом класса EventHandler, и будет предлагать подсказки >> public function getModel() < //некая фабрика возвращает объект неведомого типа //(она может возвращать разные объекты. Какой именно, будет известно исходя из переданных параметров) //но вы точно знаете, что в этом месте метод вернет вам некий класс. Пропишите его вот так: $model = NodeFactory::byId($id); /* @var $model Folder */ $model; // здесь IDE будет подсказывать вам атрибуты и методы из класса Folder >Заключение
Что бы кто не говорил, но PHP вырос до достаточно мощного инструмента. Динамическая типизация — это что позволяет быть ему максимально гибким и простым. Но вместе с ней приходят и сложности.

Статическая типизация, позволяет улучшить производительность труда и сократить количество ошибок в коде.
Из комментариев на хабре к статье Ликбез по типизации:
В задачах, сложность которых заставляет испытывать дикий восторг от возможности автоматической проверки хоть чего-либо, языки с сильной статической типизацией обгоняют всё остальное. Сложность задач решаемых при сайтостроении плавно приближается к такому уровню.
Мы не можем изменить отношение PHP к типам, да это и не нужно. Мы так же не можем взять и в одночасье перевести все свои проекты на какой либо другой язык, на это нет ни времени ни возможности.
Но благодаря правильно построенной архитектуре, использованию контроля типов в прототипах ваших функций, а так же документированию с помощью PHPDoc, можно разгрузить себя от лишней работы и поиска ошибок в ваших проектах.Придерживаясь советов, изложенных в этой статье, мы сможем объединить лучшее из двух миров, и получить мощный и гибкий инструмент разработки сложных проектов.
