Обзор моих любимых фич PHP7
Когда люди обсуждают изменения в PHP7, самое распространенное что вы слышите — это значительно улучшенный движок, который может похвастаться более быстрой скоростью выполнения и значительно меньшим объемом памяти при сравнении обычных приложений PHP, таких как Drupal, WordPress и MediaWiki.
Не поймите меня неправильно, это все конечно здорово! Мне удалось перенести несколько устаревших приложений CodeIgniter на PHP7 и достигнуть гораздо более высокой производительность с небольшими изменениями в кодовой базе. Тем не менее, PHP7 также добавляет несколько новых функций, которые могут помочь оптимизировать существующий код или повысить качество написания нового кода. Здесь я изложил несколько моих избранных фич.
Скалярный параметр и возврат заявленного типа
PHP имел объявления типов и до 7 версии, но ограничивался только объектами и массивами. PHP7 теперь обеспечивает поддержку всех скалярных типов и предлагает два разных объявления типов.
Принудительный:
это тип объявления по умолчанию и просто означает, что среда выполнения PHP будет пытаться приводить значения, когда это необходимо. Возьмем, к примеру, следующий код.
Строгий:
Второй, строгий тип, включается с помощью флага, добавленного в начало каждого файла. Когда он включен, то интерпретатор не приводит тип, как в приведенном выше примере, он отвечает ошибкой и останавливает выполнение скрипта.
Добавив единую declare инструкцию в самом начале файла, в тот же код, что и раньше, теперь мы получаем следующее сообщение об ошибке:
Fatal error: Uncaught TypeError: Argument 1 passed to reverseString() must be of the type string, integer given
Маленькое дополнение: когда вы включаете строгий режим, это также распространяется на встроенные функции и функциям PHP загружаемым из расширений.
Маленькое дополнение: Если вы работаете с JavaScript, вы можете делать такие вещи:
Это не будет работать в PHP, и эквивалентный код на PHP установит значение 0, поскольку новый оператор работает только с null значениями.
Групповые Use Declarations
При группировке вышеперечисленное может быть сокращено, как показано на примере ниже, что позволяет получить более чистый и наглядный код, что импортируется и откуда.
Константные массивы
Именованные константы — очень ценный инструмент в PHP. Одним из распространенных вариантов использования является улучшение читаемости кода путем предоставления семантических имен произвольным данным, таким как цвета, значениям RGB или магическим номерам в коде, которые неоднозначны и могут сбить с толку в других случаях.
Любой, кто работал с PHP долгое время, скорее всего, видел приложение с файлом констант (или даже несколькими файлами), которое содержит десятки, если не сотни именованных констант, требующих длинных и описательных имен, чтобы избежать конфликтов имен.
Именованные константы, в дополнение к ранее поддерживаемым типам данных, могут быть как индексированным так и ассоциативным массивом. Это поможет более точно сгруппировать многие именованные константы, которые могут быть у вас в вашем приложении.
Константы в PHP — const и define()
Объявлять константы в PHP можно двумя способами:
У каждого способа есть свои особенности, чтобы их понять, давайте рассмотрим все поэтапно, как и что менялось с каждой версией PHP.
Как создавать константы
PHP меньше 5.3
С версии PHP 5.3
Появилось ключевое слово const и теперь константу можно определять еще и с помощью него.
Однако, в const нельзя указать переменную, функцию или какое то выражение, а нужно передавать скаляр «напрямую»:
Тогда как для define() таких ограничений нет.
PHP 5.6
Стало возможным указывать в значения const примитивные PHP выражения (выражения из скаляров):
Стало возможным хранить массивы в константах:
Разница между define() и const
#1 const должны быть объявлены в верхней области
Потому что они определяются при компилировании скрипта. Это значит, что const нельзя использовать внутри функций/циклов/выражений if или try/catch блоков.
#2 const всегда регистрозависима
В то время как define() позволяет создать регистро-независимые константы:
#3 const понимает только скаляры
const нельзя передать переменные, функции, выражения, а define() можно:
С версии PHP 5.6 в const также можно указывать примитивные выражения, а не только скаляры.
#4 const может хранить массивы с версии PHP 5.6, а define с PHP 7.0
Итоги сравнения
Константы PHP класса
Объявленная константа принадлежит именно классу, она не принадлежит ни одному объекту и является общей на всех объектов (экземпляров) класса.
Константы для классов чем-то похожи на статические (static) свойства класса. Не углубляясь в подробности, разница в том, что константу нельзя изменить.
«Волшебные» константы
И в заключении вспомним про особые константы PHP.
В PHP есть девять волшебных констант, которые меняют свое значение в зависимости от контекста, в котором они используются. Например, значение __LINE__ зависит от строки в скрипте, на которой эта константа указана. Все «волшебные» константы разрешаются во время компиляции, в отличии от обычных констант, которые разрешаются во время исполнения. Специальные константы нечувствительны к регистру и их список приведен ниже:
define
(PHP 4, PHP 5, PHP 7, PHP 8)
define — Определяет именованную константу
Описание
Определяет именованную константу во время выполнения.
Список параметров
Начиная с PHP 7.3.0, определение нечувствительных к регистру констант объявлено устаревшим.
Нечувствительные к регистру константы хранятся в нижнем регистре.
Возвращаемые значения
Возвращает true в случае успешного выполнения или false в случае возникновения ошибки.
Список изменений
Примеры
Пример #1 Определение констант
Пример #2 Определение констант зарезервированными именами
Этот пример демонстрирует возможность определения константы с тем же именем, что и магическая константа. Поскольку это, очевидно, сбивающее с толку поведение, не рекомендуется делать это на практике.
Результат выполнения данного примера:
Смотрите также
User Contributed Notes 15 notes
Be aware that if «Notice»-level error reporting is turned off, then trying to use a constant as a variable will result in it being interpreted as a string, if it has not been defined.
I was working on a program which included a config file which contained:
//define(‘ENABLE_UPLOADS’, true);
?>
However, to my surprise, the program was still allowing uploads. Digging deeper into the code, I discovered this:
if ( ENABLE_UPLOADS ):
?>
Since ‘ENABLE_UPLOADS’ was not defined as a constant, PHP was interpreting its use as a string constant, which of course evaluates as True.
Not sure why the docs omit this, but when attempting to define() a constant that has already been defined, it will fail, trigger an E_NOTICE and the constant’s value will remain as it was originally defined (with the new value ignored).
(Guess that’s why they’re called «constants».)
define() will define constants exactly as specified. So, if you want to define a constant in a namespace, you will need to specify the namespace in your call to define(), even if you’re calling define() from within a namespace. The following examples will make it clear.
The following code will define the constant «MESSAGE» in the global namespace (i.e. «\MESSAGE»).
# Output
echo SOME_CONSTANT ; // prints «NEW_CONSTANT»
echo «
» ;
echo NEW_CONSTANT ; // prints «Some value»
?>
Needless to say that you’ll lose your IDE support for refactoring and highlighting completely for such cases.
No clue why someone would / could actually use this but i thought it’s worth mentioning.
The value of a constant can be the value of another constant.
echo NEW_GOOD_NAME_CONSTANT ; // current
echo OLD_BAD_NAME_CONSTANT ; // legacy
I think worth mentioning is that define() appears to ignore invalid constant names.
One immediate implication of this seem to be that if you use an invalid constant name you have to use constant() to access it and obviously that you can’t use the return value from define() to tell you whether the constant name used is invalid or not.
For example:
$name = ‘7(/!§%’;
var_dump(define($name, «hello»)); // outputs bool(true)
var_dump(constant($name)); // outputs string(5) «hello»
It may be worth stating that a define function must be executed before its global constant is referenced.
Abc();
define(«TEST», 23);
function Abc()
<
echo TEST;
> // Abc
This code fails with a Notice-level message. TEST is treated here as being the string «TEST».
There’s an undocumented side-effect of setting the third parameter to true (case-insensitive constants): these constants can actually be «redefined» as case-sensitive, unless it’s all lowercase (which you shouldn’t define anyway).
The fact is that case-sensitive constants are stored as is, while case-insensitive constants are stored in lowercase, internally. You’re still allowed to define other constants with the same name but capitalized differently (except for all lowercase).
A third party plugin might attempt to define a constant for which you already set a value. If it’s fine for them to set the new value, assuming you cannot edit the plugin, you could define your constant case-insensitive. You can still access the original value, if needed, by using any capitalization other than the one the plugin uses. As a matter of fact, I can’t think of another case where you would want a case-insensitive constant.
With php 7 you can now define arrays.
defined
(PHP 4, PHP 5, PHP 7, PHP 8)
defined — Проверяет существование указанной именованной константы
Описание
Проверяет существование и наличие значения указанной константы.
Список параметров
Возвращаемые значения
Примеры
Пример #1 Проверка констант
Смотрите также
User Contributed Notes 16 notes
// Checking the existence of a class constant, if the class is referenced by a variable.
class Class_A
<
const CONST_A = ‘value A’;
>
// When class name is known.
if ( defined( ‘Class_A::CONST_A’ ) )
echo ‘Class_A::CONST_A defined’;
// Using a class name variable. Note the double quotes.
$class_name = Class_A::class;
if ( defined( «$class_name::CONST_A» ) )
echo ‘$class_name::CONST_A defined’;
final class class2 extends class1
<
const SOME_CONST = 2 ;
>
$class2 = new class2 ;
if you want to check id a class constant is defined use self:: before the constant name:
Before using defined() have a look at the following benchmarks:
true 0.65ms
$true 0.69ms (1)
$config[‘true’] 0.87ms
TRUE_CONST 1.28ms (2)
true 0.65ms
defined(‘TRUE_CONST’) 2.06ms (3)
defined(‘UNDEF_CONST’) 12.34ms (4)
isset($config[‘def_key’]) 0.91ms (5)
isset($config[‘undef_key’]) 0.79ms
isset($empty_hash[$good_key]) 0.78ms
isset($small_hash[$good_key]) 0.86ms
isset($big_hash[$good_key]) 0.89ms
isset($small_hash[$bad_key]) 0.78ms
isset($big_hash[$bad_key]) 0.80ms
PHP Version 5.2.6, Apache 2.0, Windows XP
Each statement was executed 1000 times and while a 12ms overhead on 1000 calls isn’t going to have the end users tearing their hair out, it does throw up some interesting results when comparing to if(true):
May want to avoid if(defined(‘DEBUG’)).
I saw that PHP doesn’t have an enum function so I created my own. It’s not necessary, but can come in handy from time to time.
This function, along with constant(), is namespace sensitive. And it might help if you imagine them always running under the «root namespace»:
Dont forget to put the name of your constant into single quotation mark. You will not get an error or a warning.
//output: 12
?>
It took me half an day to see it.
In PHP5, you can actually use defined() to see if an object constant has been defined, like so:
class Generic
<
const WhatAmI = ‘Generic’ ;
>
if ( defined ( ‘Generic::WhatAmI’ ))
<
echo Generic :: WhatAmI ;
>
?>
Thought it may be useful to note.

Очень и очень удобная вещь для скриптового языка. Но, все же имеющая свои плюсы и минусы.
Причем возможность динамически определять глобальные константы применяется не только для настроек. Так. например, константы часто используются для защиты от прямого вызова вложенных файлов. Выглядит это так.
Есть основной файл index.php
И есть какой-нибудь файл движка engine.php, где в первых же строках проверяется наличие этой константы
Таким образом, если вы попробуете открыть engine.php напрямую, то ничего не произойдет, чтобы после первой строки не шло. Очень удобный, простой и главное эффективны способ защиты от прямого вызова файлов.
Примечание: Конечно, стоит понимать, что это не панацея. Если у взломщика есть возможность менять или создавать файлы, или же у вас в коде ошибки, или же вы где-то оставили тестовый файл php, то такая защита не очень-то и поможет.
Чаще же всего именованные константы используются для создания файлов конфигураций, определения различного рода переключателей и даже в некоторых ситуациях хранят промежуточные данные, ведь константы можно объявлять динамически и они хранятся только для выполняемого процесса на время его существования.
Однако, есть ряд нюансов, которые необходимо понимать, в противном случае из удобного механизма очень легко получить массу проблем (приведу парочку).
1. Константы нельзя переопределять.
Вы все оттестировали, померили скорость, порадовались результату и прочее.
Прошло время и люди стали использовать вашу библиотеку не только в своих самописных проектах, но и в дополнении к различным CMS. Все радовались и бегали по лужам. Однако, в один момент оказалось, что в одной из CMS была добавлена константа в файле конфигурации, из-за которой библиотека сыпалась с «Fatal Error». После долгих разбирательств, вы обнаружили, что смело использовали короткое и удобное название одной из констант.
А теперь, представьте сколько времени займет замена одной этой несчастной константы? Впрочем, такая проблема говорит о необходимости полной замены имен констант, но об этом чуть далее. Отвечая на вопрос, нет это не только «Поиск и замена» в любом из редакторов (к примеру, Notepad++). Это так же и полная перепроверка всей функциональности, плюс оповещение пользователей, чтобы они смогли переконфигурировать вашу библиотеку в своих проектах.
Таким образом, вы всегда должны помнить, что ваши константы должны иметь уникальные имена (префикс библиотеки или нечто подобное), тем самым превращаясь в длинные строки (нередко константы бывают и длиной по 100-120 символов). В противном случае, всегда будут проблемы с интеграцией.
2. Используемых для настройки констант должно быть ограниченное и вменяемое количество.
Если вы что-то писали под CMS или же просто интересовались доступными настройками, то, вероятно, замечали что их порядка 10-20, несмотря на огромные объемы кода. Конечно, же всегда существуют и системные константы для удобства использования, которые можно встретить только лишь в самом ядре системы, но сути это не меняет.
Если количество констант в вашем коде становится слишком много, то со временем использовать такой код становится практически невозможно. И тут есть несколько причин.
Во-вторых, вопрос архитектуры. Если в коде есть большое количество констант, то это один из признаков, что архитектура проекта имеет проблемы. И речь не идет о количестве настроек. Так, например, в любой CMS с кучей установленных модулей, настроек невероятно много. Однако, все эти настройки распределены между разными механизмами, такими как банальная таблица в БД. Поэтому код остается читаемым, легко настраиваемым и относительно универсальным.
В-третьих, вопрос корректировки кода. Каждое исправление или же корректировка кода с необходимостью добавления, редактирования или удаления констант будет весьма неожиданным сюрпризом для других пользователей. А все банально потому, что если требуется переконфигурация или импорт старых настроек, то сделать это будет нереально, так как «где, как и что» пользователь использовал, вы не можете заранее определить.
Таким образом, если количество настроек серьезно расширяется, то лучше разделить их на глобальные, такие как доступ к БД (то есть те, без которых код не запустится), и те, для которых можно использовать прочие механизмы (например, загрузка констант из той же БД в класс обертку, не позволяющую редактировать данные).
3. Константы не хранят объекты, только простые данные.
Одним из весьма существенных ограничений является то, что константы не хранят объекты данных. Конечно, с версии 5.6 PHP, стала возможность поддержки массивов данных, которые можно использовать как аналог объектов. Однако, советовал бы воздерживаться от этого механизма без особой нужды, ведь для этого есть более удобные варианты..
Но, возвращаясь. Другими словами, константы это механизмы функционального подхода. Это означает, что если вы применяете ООП, то наросты констант с настройками будут лишь существенно усложнять код. Что-то вроде этого:
Такой подход невероятно усложняет поиск ошибок и проблем, особенно учитывая то, что сами эти PARAM`s могут определяться динамически.
Примечание: Если же от константах никак не избавиться, то старайтесь выносить их парсинг и интерпретацию в конструктор класса или же отдельный метод, чтобы внутри остальных функций не было таких вставок и чтобы параметры не расползались по всему коду. В противном случае, будет весьма запутанный класс, поведение которого легко может меняться вообще в других участках кода, без прямого обращения к объектам класса. К примеру, просто объявив одну из настроек.
Как видите, у именованных констант есть свои нюансы, которые необходимо учитывать.
