Список 10 самых распространенных ошибок разработчиков PHP

  1. Распространенная ошибка № 1: Оставление висячих ссылок на массивы после циклов foreach
  2. Распространенная ошибка №2: недопонимание поведения isset ()
  3. Распространенная ошибка № 3: путаница с возвратом по ссылке или по значению
  4. Распространенная ошибка № 5: подделки в использовании памяти и неэффективность
  5. Распространенная ошибка №6: игнорирование проблем с Unicode / UTF-8
  6. Распространенная ошибка № 7: при условии, что $ _POST всегда будет содержать ваши данные POST
  7. Распространенная ошибка № 8: думая, что PHP поддерживает символьный тип данных
  8. Распространенная ошибка № 9: игнорирование стандартов кодирования
  9. Распространенная ошибка № 10: злоупотребление пустым ()
  10. Заворачивать

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

PHP разработчики

Распространенная ошибка № 1: Оставление висячих ссылок на массивы после циклов foreach

Не знаете, как использовать циклы foreach в PHP? Использование ссылок в для каждого Циклы могут быть полезны, если вы хотите работать с каждым элементом в массиве, который вы перебираете. Например:

$ arr = array (1, 2, 3, 4); foreach ($ arr as & $ value) {$ value = $ value * 2; } // $ arr теперь массив (2, 4, 6, 8)

Проблема в том, что, если вы не будете осторожны, это также может иметь нежелательные побочные эффекты и последствия. В частности, в приведенном выше примере после выполнения кода $ value останется в области видимости и будет содержать ссылку на последний элемент в массиве. Последующие операции, включающие $ value, могут непреднамеренно изменить последний элемент в массиве.

Главное помнить, что foreach не создает область видимости. Таким образом, $ value в приведенном выше примере является ссылкой в верхней части скрипта. На каждой итерации foreach устанавливает ссылку для указания следующего элемента массива $. Поэтому после завершения цикла $ value все еще указывает на последний элемент массива $ и остается в области видимости.

Вот пример уклончивых и сбивающих с толку ошибок, к которым это может привести:

$ array = [1, 2, 3]; echo implode (',', $ array), "\ n"; foreach ($ array as & $ value) {} // по ссылке echo implode (',', $ array), "\ n"; foreach ($ массив как $ значение) {} // по значению (то есть, копировать) echo implode (',', $ array), "\ n";

Приведенный выше код выведет следующее:

1,2,3 1,2,3 1,2,2

Нет, это не опечатка. Последнее значение в последней строке действительно 2, а не 3.

Почему?

После прохождения первого цикла foreach $ array остается неизменным, но, как объяснено выше, $ value остается в виде висячей ссылки на последний элемент в массиве $ (поскольку этот цикл foreach обращался к $ value по ссылке ).

В результате, когда мы проходим второй цикл foreach, «странные вещи», кажется, происходят. В частности, поскольку доступ к $ value теперь осуществляется по значению (т. Е. По копированию ), foreach копирует каждый последовательный элемент массива $ в $ value на каждом шаге цикла. В результате вот что происходит на каждом этапе второго цикла foreach:

  • Пропуск 1: Копирует $ array [0] (т.е. «1») в $ value (который является ссылкой на $ array [2]), поэтому $ array [2] теперь равно 1. Так что $ array теперь содержит [1, 2, 1].
  • Пропуск 2: копирует $ array [1] (т.е. «2») в $ value (который является ссылкой на $ array [2]), поэтому $ array [2] теперь равно 2. Так что $ array теперь содержит [1, 2, 2].
  • Пропуск 3: Копирует $ array [2] (который теперь равен «2») в $ value (который является ссылкой на $ array [2]), поэтому $ array [2] по-прежнему равен 2. Таким образом, $ array теперь содержит [1 , 2, 2].

Чтобы по-прежнему получать преимущества от использования ссылок в циклах foreach без риска возникновения подобных проблем, вызовите unset () для переменной сразу после цикла foreach, чтобы удалить ссылку; например:

$ arr = array (1, 2, 3, 4); foreach ($ arr as & $ value) {$ value = $ value * 2; } unset ($ value); // $ value больше не ссылается на $ arr [3]

Распространенная ошибка №2: недопонимание поведения isset ()

Несмотря на свое название, Исеть () не только возвращает false, если элемент не существует, но также возвращает false для нулевых значений .

Такое поведение более проблематично, чем может показаться на первый взгляд, и является распространенным источником проблем.

Учтите следующее:

$ data = fetchRecordFromStorage ($ storage, $ identifier); if (! isset ($ data ['keyShouldBeSet']) {// сделать что-то здесь, если 'keyShouldBeSet' не установлено}

Автор этого кода предположительно хотел проверить, установлен ли keyShouldBeSet в $ data. Но, как уже говорилось, isset ($ data ['keyShouldBeSet']) также будет возвращать значение false, если $ data ['keyShouldBeSet'] было установлено, но было установлено значение null. Таким образом, приведенная выше логика ошибочна.

Вот еще один пример:

if ($ _POST ['active']) {$ postData = extractSomething ($ _ POST); } // ... if (! isset ($ postData)) {echo 'post not active'; }

Приведенный выше код предполагает, что если $ _POST ['active'] вернет true, тогда postData будет обязательно установлен, и поэтому isset ($ postData) вернет true. И наоборот, в приведенном выше коде предполагается, что единственный способ, которым isset ($ postData) вернет false, это если $ _POST ['active'] также вернул false.

Не.

Как объяснено, isset ($ postData) также вернет false, если для $ postData было установлено значение null Поэтому isset ($ postData) может вернуть false, даже если $ _POST ['active'] вернул true. Итак, еще раз, вышеуказанная логика является ошибочной.

И, между прочим, в качестве дополнительного замечания, если целью в приведенном выше коде действительно было снова проверить, вернул ли $ _POST ['active'] значение true, полагаясь на isset (), так как в любом случае это было плохим решением при кодировании. Вместо этого было бы лучше просто перепроверить $ _POST ['active']; то есть:

if ($ _POST ['active']) {$ postData = extractSomething ($ _ POST); } // ... if ($ _POST ['active']) {echo 'post not active'; }

Однако в тех случаях, когда важно проверить, действительно ли установлена ​​переменная (т. Е. Чтобы различить переменную, которая не была установлена, и переменную, для которой было установлено значение null), array_key_exists () Метод является гораздо более надежным решением.

Например, мы могли бы переписать первый из двух приведенных выше примеров следующим образом:

$ data = fetchRecordFromStorage ($ storage, $ identifier); if (! array_key_exists ('keyShouldBeSet', $ data)) {// сделать это, если 'keyShouldBeSet' не установлен}

Кроме того, путем объединения array_key_exists () с get_defined_vars () , мы можем надежно проверить, установлена ​​ли переменная в текущей области или нет:

if (array_key_exists ('varShouldBeSet', get_defined_vars ())) {// переменная $ varShouldBeSet существует в текущей области}

Распространенная ошибка № 3: путаница с возвратом по ссылке или по значению

Рассмотрим этот фрагмент кода:

class Config {private $ values ​​= []; public function getValues ​​() {return $ this-> values; }} $ config = new Config (); $ config-> getValues ​​() ['test'] = 'test'; echo $ config-> getValues ​​() ['test'];

Если вы запустите приведенный выше код, вы получите следующее:

Примечание PHP: неопределенный индекс: тест в /path/to/my/script.php в строке 21

В чем дело?

Проблема заключается в том, что приведенный выше код путает возврат массивов по ссылке с возвращением массивов по значению. Если вы явно не скажете PHP возвращать массив по ссылке (то есть, используя &), PHP по умолчанию вернет массив «по значению». Это означает, что будет возвращена копия массива, и поэтому вызываемая функция и вызывающая сторона не будут обращаться к одному и тому же экземпляру массива.

Поэтому приведенный выше вызов getValues ​​() возвращает копию массива $ values, а не ссылку на него. Имея это в виду, давайте вернемся к двум ключевым строкам из приведенного выше примера:

// getValues ​​() возвращает COPY массива $ values, так что это добавляет элемент «test» // в COPY массива $ values, но не в сам массив $ values. $ config-> getValues ​​() ['test'] = 'test'; // getValues ​​() снова возвращает ДРУГУЮ КОПИЮ массива $ values, и эта копия // не содержит элемента «test» (именно поэтому мы получаем сообщение «undefined index»). echo $ config-> getValues ​​() ['test'];

Одним из возможных исправлений было бы сохранение первой копии массива $ values, возвращенной getValues ​​(), а затем последующая обработка этой копии; например:

$ vals = $ config-> getValues ​​(); $ vals ['test'] = 'test'; echo $ vals ['test'];

Этот код будет работать нормально (т. Е. Он будет выводить тест без создания сообщения «неопределенный индекс»), но в зависимости от того, что вы пытаетесь выполнить, этот подход может быть или не быть адекватным. В частности, приведенный выше код не будет изменять исходный массив $ values. Поэтому, если вы хотите, чтобы ваши изменения (например, добавление элемента 'test') влияли на исходный массив, вам вместо этого нужно изменить функцию getValues ​​(), чтобы она возвращала ссылку на сам массив $ values. Это делается путем добавления символа & перед именем функции, что указывает на то, что она должна возвращать ссылку; то есть:

class Config {private $ values ​​= []; // возвращаем ссылку на массив фактических значений $ public function & getValues ​​() {return $ this-> values; }} $ config = new Config (); $ config-> getValues ​​() ['test'] = 'test'; echo $ config-> getValues ​​() ['test'];

Результатом этого будет тест, как и ожидалось.

Но чтобы сделать вещи более запутанными, рассмотрите вместо этого следующий фрагмент кода:

class Config {private $ values; // использование ArrayObject вместо массива public function __construct () {$ this-> values ​​= new ArrayObject (); } публичная функция getValues ​​() {return $ this-> values; }} $ config = new Config (); $ config-> getValues ​​() ['test'] = 'test'; echo $ config-> getValues ​​() ['test'];

Если вы догадались, что это приведет к той же ошибке «неопределенный индекс», что и в нашем предыдущем примере с массивом, вы ошиблись. На самом деле этот код будет работать просто отлично. Причина в том, что, в отличие от массивов, PHP всегда передает объекты по ссылке . (ArrayObject - это объект SPL, который полностью имитирует использование массивов, но работает как объект.)

Как показывают эти примеры, в PHP не всегда очевидно, имеете ли вы дело с копией или ссылкой. Поэтому важно понимать эти поведения по умолчанию (т. Е. Переменные и массивы передаются по значению; объекты передаются по ссылке), а также тщательно проверять документацию API для функции, которую вы вызываете, чтобы увидеть, возвращает ли она значение, копия массива, ссылка на массив или ссылка на объект.

При этом важно отметить, что практики возврата ссылки на массив или ArrayObject, как правило, следует избегать, так как он предоставляет вызывающей стороне возможность изменять личные данные экземпляра. Это «бросает вызов» инкапсуляции. Вместо этого лучше использовать «геттеры» и «сеттеры» старого стиля, например:

class Config {private $ values ​​= []; открытая функция setValue ($ key, $ value) {$ this-> values ​​[$ key] = $ value; } публичная функция getValue ($ key) {вернуть $ this-> values ​​[$ key]; }} $ config = new Config (); $ config-> setValue ('testKey', 'testValue'); echo $ config-> getValue ('testKey'); // echos 'testValue'

Этот подход дает вызывающей стороне возможность устанавливать или получать любое значение в массиве, не предоставляя публичный доступ к самому частному массиву $ values.

Нередко встречается нечто подобное, если ваш PHP не работает:

$ models = []; foreach ($ inputValues ​​как $ inputValue) {$ models [] = $ valueRepository-> findByValue ($ inputValue); }

Хотя здесь не может быть абсолютно ничего плохого, но если вы будете следовать логике в коде, вы можете обнаружить, что невинно выглядящий вызов выше $ valueRepository-> findByValue () в конечном итоге приводит к какому-то запросу, например:

$ result = $ connection-> query ("SELECT` x`, `y` FROM` values` WHERE `value` =". $ inputValue);

В результате каждая итерация вышеуказанного цикла приведет к отдельному запросу к базе данных. Так что, если, например, вы предоставили в цикл массив из 1000 значений, он сгенерирует 1000 отдельных запросов к ресурсу! Если такой скрипт вызывается в нескольких потоках, он может привести к полной остановке системы.

Поэтому очень важно распознавать, когда ваш код выполняет запросы, и, когда это возможно, собирать значения и затем запускать один запрос, чтобы получить все результаты.

Одним из примеров довольно распространенного места, где встречаются запросы, выполняемые неэффективно (т.е. в цикле), является случай, когда форма публикуется со списком значений (например, идентификаторами). Затем, чтобы получить полные данные записи для каждого из идентификаторов, код будет циклически проходить по массиву и выполнять отдельный запрос SQL для каждого идентификатора. Это часто будет выглядеть примерно так:

$ data = []; foreach ($ ids as $ id) {$ result = $ connection-> query ("SELECT` x`, `y` FROM` values` WHERE `id` =". $ id); $ data [] = $ result-> fetch_row (); }

Но та же самая вещь может быть выполнена намного более эффективно в одном запросе SQL следующим образом:

$ data = []; if (count ($ ids)) {$ result = $ connection-> query ("SELECT` x`, `y` FROM` values` WHERE `id` IN (". implode (',', $ ids)); while ($ row = $ result-> fetch_row ()) {$ data [] = $ row;}}

Поэтому очень важно распознавать, когда запросы выполняются, прямо или косвенно, вашим кодом. Когда это возможно, соберите значения и затем выполните один запрос, чтобы получить все результаты. Тем не менее, здесь следует проявлять осторожность, что приводит нас к нашей следующей распространенной ошибке в PHP…

Распространенная ошибка № 5: подделки в использовании памяти и неэффективность

Хотя выборка сразу нескольких записей определенно более эффективна, чем запуск одного запроса для каждой строки для выборки, такой подход может потенциально привести к состоянию «недостаточно памяти» в libmysqlclient при использовании PHP-расширения mysql.

Чтобы продемонстрировать, давайте взглянем на тестовую коробку с ограниченными ресурсами (512 МБ ОЗУ), MySQL и php-cli.

Мы загрузим таблицу базы данных следующим образом:

// подключаемся к mysql $ connection = new mysqli ('localhost', 'username', 'password', 'database'); // создать таблицу из 400 столбцов $ query = 'CREATE TABLE `test` (` id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT'; for ($ col = 0; $ col <400; $ col ++) {$ query. = ", `col $ col` CHAR (10) NOT NULL";} $ query. = ');'; $ Connection-> запрос ($ запроса); // записать 2 миллиона строк для ($ row = 0; $ row <2000000; $ row ++) {$ query = "INSERT INTO` test` VALUES ($ row "; for ($ col = 0; $ col <400; $ col ++) {$ query. = ','. mt_rand (1000000000, 9999999999);} $ query. = ')'; $ Connection-> запрос ($ запроса); }

Хорошо, теперь давайте проверим использование ресурсов:

// подключаемся к mysql $ connection = new mysqli ('localhost', 'username', 'password', 'database'); эхо "До:". memory_get_peak_usage (). "\ П"; $ res = $ connection-> query ('SELECT `x`,` y` FROM `test` LIMIT 1'); эхо "Предел 1:". memory_get_peak_usage (). "\ П"; $ res = $ connection-> query ('SELECT `x`,` y` FROM `test` LIMIT 10000'); эхо "Предел 10000:". memory_get_peak_usage (). "\ П";

Выход:

До: 224704 Лимит 1: 224704 Лимит 10000: 224704

Здорово. Похоже, что запрос безопасно управляется внутри с точки зрения ресурсов.

Но чтобы быть уверенным, давайте еще раз увеличим лимит и установим его на 100 000. Ой-ой. Когда мы это делаем, мы получаем:

Предупреждение PHP: mysqli :: query (): (HY000 / 2013): потеря соединения с сервером MySQL во время запроса в /root/test.php в строке 11

Что произошло?

Проблема здесь в том, как работает PHP-модуль mysql. Это действительно просто прокси для libmysqlclient, который делает грязную работу. Когда часть данных выбрана, она попадает прямо в память. Поскольку эта память не управляется PHP-менеджером, memory_get_peak_usage () не будет показывать никакого увеличения использования ресурсов, когда мы увеличиваем ограничение в нашем запросе. Это приводит к проблемам, подобным той, которая была продемонстрирована выше, когда мы обмануты, думая, что с нашей памятью все в порядке. Но на самом деле, наше управление памятью серьезно испорчено, и мы можем испытывать проблемы, подобные показанной выше.

Вы можете по крайней мере избежать вышеупомянутого подделки (хотя это само по себе не улучшит использование вашей памяти), вместо этого используя модуль mysqlnd. mysqlnd скомпилирован как собственное расширение PHP и использует менеджер памяти PHP.

Поэтому, если мы запустим вышеуказанный тест, используя mysqlnd, а не mysql, мы получим гораздо более реалистичную картину использования нашей памяти:

До: 232048 Лимит 1: 324952 Лимит 10000: 32572912

И это еще хуже, кстати. Согласно документации PHP, mysql использует вдвое больше ресурсов, чем mysqlnd, для хранения данных, поэтому оригинальный скрипт, использующий mysql, действительно использовал даже больше памяти, чем показано здесь (примерно вдвое больше).

Чтобы избежать таких проблем, подумайте об ограничении размера ваших запросов и использовании цикла с небольшим количеством итераций; например:

$ totalNumberToFetch = 10000; $ partSize = 100; for ($ i = 0; $ i <= ceil ($ totalNumberToFetch / $ partSize); $ i ++) {$ limitFrom = $ partSize * $ i; $ res = $ connection-> query ("SELECT` x`, `y` FROM` test` LIMIT $ limitFrom, $ partSize "); }

Когда мы рассматриваем как эту ошибку PHP, так и ошибка № 4 Выше мы понимаем, что существует идеальный баланс, которого в идеале должен достичь ваш код, с одной стороны, с тем, чтобы ваши запросы были слишком детализированными и повторяющимися, и с тем, чтобы каждый из ваших индивидуальных запросов был слишком большим. Как и в большинстве вещей в жизни, необходим баланс; либо экстрим нехорош и может вызвать проблемы с неработающим PHP.

Распространенная ошибка №6: игнорирование проблем с Unicode / UTF-8

В некотором смысле, это действительно большая проблема в самом PHP, чем та, с которой вы столкнулись бы при отладке PHP, но она никогда не была должным образом решена. Ядро PHP 6 должно было стать ориентированным на Unicode, но это было приостановлено, когда разработка PHP 6 была приостановлена ​​еще в 2010 году.

Но это никоим образом не освобождает разработчика от правильно вручая UTF-8 и избегая ошибочного предположения, что все строки обязательно будут «простым старым ASCII». Код, который не может правильно обрабатывать строки не-ASCII, печально известен тем, что вводит gnarly гейзенбагами в ваш код. Даже простые вызовы strlen ($ _ POST ['name']) могут вызвать проблемы, если кто-то с фамилией, такой как «Шредингер», попытается зарегистрироваться в вашей системе.

Вот небольшой контрольный список, чтобы избежать таких проблем в вашем коде:

  • Если вы мало знаете о Unicode и UTF-8, вы должны хотя бы изучить основы. Там отличный учебник для начинающих Вот ,
  • Обязательно всегда используйте mb_ * функции вместо старых строковых функций (убедитесь, что расширение «multibyte» включено в вашу сборку PHP).
  • Убедитесь, что ваша база данных и таблицы настроены на использование Unicode (во многих сборках MySQL по-прежнему используется latin1).
  • Помните, что json_encode () преобразует символы, не входящие в ASCII (например, «Schrödinger» становится «Schr \ u00f6dinger»), а serialize () - нет .
  • Убедитесь, что ваши файлы PHP-кода также имеют кодировку UTF-8, чтобы избежать коллизий при объединении строк с жестко закодированными или настроенными строковыми константами.

Особенно ценным ресурсом в этом отношении является UTF-8 Primer для PHP и MySQL пост от Франциско Клария в этом блоге.

Распространенная ошибка № 7: при условии, что $ _POST всегда будет содержать ваши данные POST

Несмотря на свое имя, массив $ _POST не всегда будет содержать ваши данные POST и может быть легко найден пустым. Чтобы понять это, давайте посмотрим на пример. Предположим, что мы делаем запрос к серверу с помощью вызова jQuery.ajax () следующим образом:

// js $ .ajax ({url: 'http://my.site/some/path', метод: 'post', data: JSON.stringify ({a: 'a', b: 'b'}) , contentType: 'application / json'});

(Кстати, обратите внимание на contentType: 'application / json' здесь. Мы отправляем данные в виде JSON, что довольно популярно для API. По умолчанию, например, для публикации в AngularJS $ http сервис .)

На серверной стороне нашего примера мы просто выводим массив $ _POST:

// php var_dump ($ _ POST);

Удивительно, но результатом будет:

массив (0) {}

Почему? Что случилось с нашей строкой JSON {a: 'a', b: 'b'}?

Ответ заключается в том, что PHP анализирует полезную нагрузку POST автоматически только тогда, когда он имеет тип содержимого application / x-www-form-urlencoded или multipart / form-data. Причины этого исторические - эти два типа контента были, по сути, единственными, которые использовались несколько лет назад, когда в PHP был реализован $ _POST. Так что с любым другим типом контента (даже с тем, который сегодня довольно популярен, например, application / json), PHP не загружает полезную нагрузку POST автоматически.

Так как $ _POST является суперглобальным, если мы переопределим его один раз (желательно в начале нашего скрипта), то измененное значение (то есть, включая полезную нагрузку POST) будет тогда ссылаться на весь наш код. Это важно, поскольку $ _POST обычно используется средами PHP и почти всеми пользовательскими сценариями для извлечения и преобразования данных запроса.

Так, например, при обработке полезной нагрузки POST с типом содержимого application / json нам необходимо вручную проанализировать содержимое запроса (т. Е. Декодировать данные JSON) и переопределить переменную $ _POST следующим образом:

// php $ _POST = json_decode (file_get_contents ('php: // input'), true);

Затем, когда мы выгружаем массив $ _POST, мы видим, что он правильно включает полезную нагрузку POST; например:

array (2) {["a"] => string (1) "a" ["b"] => string (1) "b"}

Распространенная ошибка № 8: думая, что PHP поддерживает символьный тип данных

Посмотрите на этот образец кода и попытайтесь угадать, что он будет печатать:

for ($ c = 'a'; $ c <= 'z'; $ c ++) {echo $ c. "\ П"; }

Если вы ответили «от» до «z», вы можете быть удивлены, узнав, что вы ошиблись.

Да, он будет печатать «а» через «z», но затем он также будет печатать «аа» через «yz». Посмотрим почему.

В PHP нет типа данных char; доступна только строка Имея это в виду, увеличение строки z в PHP приводит к aa:

php> $ c = 'z'; echo ++ $ c. "\ П"; аа

Тем не менее, чтобы еще больше запутать вопросы, aa лексикографически меньше z:

php> var_export ((логическое) ('aa' <'z')). "\ П"; правда

Вот почему приведенный выше пример кода печатает буквы от a до z, а затем печатает от aa до yz. Он останавливается, когда достигает za, что является первым значением, с которым он сталкивается, что он «больше чем» z:

php> var_export ((логическое) ('za' <'z')). "\ П"; ложный

В таком случае, вот один из способов правильно перебрать значения от 'a' до 'z' в PHP:

for ($ i = ord ('a'); $ i <= ord ('z'); $ i ++) {echo chr ($ i). "\ П"; }

Или в качестве альтернативы:

$ letters = range ('a', 'z'); for ($ i = 0; $ i <count ($ letters); $ i ++) {echo $ letters [$ i]. "\ П"; }

Распространенная ошибка № 9: игнорирование стандартов кодирования

Хотя игнорирование стандартов кодирования напрямую не приводит к необходимости отладки PHP-кода, тем не менее, это, вероятно, одна из самых важных вещей для обсуждения здесь.

Игнорирование стандартов кодирования может вызвать целый ряд проблем в проекте. В лучшем случае это приводит к несовместимости кода (поскольку каждый разработчик «делает свое дело»). Но в худшем случае он создает код PHP, который не работает или может быть трудным (иногда почти невозможным) для навигации, что делает его чрезвычайно трудным для отладки, улучшения, сопровождения. А это означает снижение производительности для вашей команды, в том числе много потерянных (или, по крайней мере, ненужных) усилий.

К счастью для разработчиков PHP, существует Рекомендация по стандартам PHP (PSR), состоящая из следующих пяти стандартов:

Изначально PSR был создан на основе материалов, предоставленных разработчиками самых известных платформ на рынке. Zend, Drupal, Symfony, Joomla и другие способствовали этим стандартам, и теперь следуем им. Даже PEAR, которая пыталась стать стандартом в течение многих лет до этого, теперь участвует в PSR.

В некотором смысле, почти не имеет значения, какой у вас стандарт кодирования, если вы согласны со стандартом и придерживаетесь его, но, как правило, следование PSR - хорошая идея, если у вашего проекта нет веских причин поступать иначе. , Все больше и больше команд и проектов соответствуют PSR. На данный момент Tt определенно признан «стандартом» большинством разработчиков PHP, поэтому его использование поможет убедиться, что новые разработчики знакомы и знакомы с вашим стандартом кодирования, когда присоединяются к вашей команде.

Распространенная ошибка № 10: злоупотребление пустым ()

Некоторые разработчики PHP любят использовать empty () для логических проверок практически всего. Однако есть случаи, когда это может привести к путанице.

Сначала вернемся к массивам и экземплярам ArrayObject (которые имитируют массивы). Учитывая их сходство, легко предположить, что массивы и экземпляры ArrayObject будут вести себя одинаково. Это, однако, оказывается опасным предположением. Например, в PHP 5.0:

// PHP 5.0 или более поздняя версия: $ array = []; var_dump (пусто ($ массив)); // выводит bool (true) $ array = new ArrayObject (); var_dump (пусто ($ массив)); // выводит bool (false) // почему они оба не выдают одинаковый вывод?

И что еще хуже, до PHP 5.0 результаты были бы другими:

// До PHP 5.0: $ array = []; var_dump (пусто ($ массив)); // выводит bool (false) $ array = new ArrayObject (); var_dump (пусто ($ массив)); // выводит bool (false)

Этот подход, к сожалению, довольно популярен. Например, это способ Zend \ Db \ TableGateway Zend Framework 2 возвращает данные при вызове current () для результата TableGateway :: select (), как предполагает документ. Разработчик может легко стать жертвой этой ошибки с такими данными.

Чтобы избежать этих проблем, лучший подход к проверке пустых структур массива состоит в использовании count ():

// Обратите внимание, что это работает во ВСЕХ версиях PHP (до и после 5.0): $ array = []; var_dump (количество ($ массив)); // выводит int (0) $ array = new ArrayObject (); var_dump (количество ($ массив)); // выводит int (0)

И, кстати, поскольку PHP переводит 0 в false, count () также может использоваться в условиях if () для проверки наличия пустых массивов. Также стоит отметить, что в PHP count () - это постоянная сложность (операция O (1)) для массивов, что делает еще более ясным, что это правильный выбор.

Другой пример, когда empty () может быть опасным, - это объединение его с функцией магического класса __get (). Давайте определим два класса и будем иметь свойство test в обоих.

Сначала давайте определим класс Regular, который включает тест как обычное свойство:

class Regular {public $ test = 'value'; }

Затем давайте определим класс Magic, который использует оператор magic __get () для доступа к свойству test:

class Magic {private $ values ​​= ['test' => 'value']; публичная функция __get ($ key) {if (isset ($ this-> values ​​[$ key]))) {вернуть $ this-> values ​​[$ key]; }}}

Хорошо, теперь давайте посмотрим, что происходит, когда мы пытаемся получить доступ к свойству test каждого из этих классов:

$ регулярный = новый регулярный (); var_dump ($ регуляризовапо> тест); // выводит string (4) "value" $ magic = new Magic (); var_dump ($ magic-> тест); // выводит строку (4) «значение»

Хорошо пока.

Но теперь давайте посмотрим, что происходит, когда мы вызываем empty () для каждого из них:

var_dump (пусто ($ регуляризовапо> тест)); // выводит bool (false) var_dump (empty ($ magic-> test)); // выводит bool (true)

Тьфу. Так что, если мы полагаемся на empty (), мы можем быть введены в заблуждение, полагая, что свойство test $ magic является пустым, тогда как в действительности оно установлено в значение «value».

К сожалению, если класс использует волшебную функцию __get () для получения значения свойства, нет надежного способа проверить, является ли значение этого свойства пустым или нет. Вне области видимости класса вы действительно можете только проверить, будет ли возвращено нулевое значение, и это не обязательно означает, что соответствующий ключ не установлен, поскольку на самом деле он мог быть установлен в нулевое значение.

Напротив, если мы попытаемся сослаться на несуществующее свойство экземпляра класса Regular, мы получим уведомление, подобное следующему:

Примечание: неопределенное свойство: Regular :: $ nonExistantTest в /path/to/test.php в строке 10, стек вызовов: 0,0012 234704 1. {main} () /path/to/test.php:0

Таким образом, главное здесь заключается в том, что метод empty () следует использовать с осторожностью, поскольку он может привести к путанице - или даже может ввести в заблуждение - результаты, если не соблюдать осторожность.

Заворачивать

Простота использования PHP может усыпить разработчиков ложным чувством комфорта, оставляя их уязвимыми для длительной отладки PHP из-за некоторых нюансов и особенностей языка. Это может привести к тому, что PHP не будет работать, и проблемы, подобные описанным здесь.

Язык PHP значительно изменился за 20-летнюю историю. Ознакомление с его тонкостями - это стоящее начинание, поскольку оно поможет обеспечить программное обеспечение, которое вы производите более масштабируемый, надежный и обслуживаемый.

Похожие

Не будет общеевропейского мБанка
Commerzbank подал в отставку от дальнейшей работы над проектом Copernicus, который предполагал международную экспансию на базе mBank Copernicus wurde begraben - сотрудники специальной секции mBank в среду узнали о недавно арендованном офисном здании Zebra специально для своих помещений. Днем ранее о смерти проекта в интервью газете Handelsblatt объявил Михаэль Мандель, член правления Commerzbank: «Мы решили не продолжать проект Коперника».
Что такое раздел восстановления?
... покупаете портативный компьютер, вы можете встретить его в разделе Recovery. Его создают все больше производителей лаптува. Что такое раздел, какую функцию он выполняет, для чего он может быть полезен? Мы объясним в этом совете. Большинство производителей ноутбуков (включая HP, Acer) выделяют скрытый, скрытый раздел (около 10 ГБ) на жестком диске, который невидим для операционной системы. На нем размещен образ установочного диска операционной системы. В случае сбоя системы при запуске
Что такое сексуальная химия?
Ты помнишь первого мальчика, который тебе понравился? Момент, когда вы поняли, что многие ваши коллеги интересны? Помните ли вы свое первое влюбление, когда вы оказались в дыре, когда увидели другого человека, и ваше сердце билось как сумасшедший? Эти моменты являются первыми признаками сексуальной химии. «Даже когда прошли годы с первых юношеских немощей, сексуальная химия для нас это остается такой же загадкой,
... чтобы оно соответствовало действующим правилам? Вариант электронной почты ( mail ) О проблемах с обв...
... чтобы оно соответствовало действующим правилам? Вариант электронной почты ( mail ) О проблемах с обвинение по электронной почте ( почта или электронная почта ) Я недавно написал.
Планшет - купить с Wi-Fi или 3G? => Tablety.pl
таблетка как типичное мобильное устройство мы ассоциируем в первую очередь доступ к Интернету из любой точки мира. Зачастую при принятии решения о покупке планшета мы выбираем вариант с модулем, обеспечивающим связь в сетях 3G. Однако необходимо ли это? Оказывается, не всегда. Есть и другие способы, которые позволят нам обеспечить подключение в сотовых сетях и в то же время сэкономить несколько сотен злотых на самом планшете.
WhatsApp для Android: всегда загружайте его из Google Play!
Становясь популярными, они превращаются в настоящую опасность. Чем известнее приложение , тем больше вероятность, что оно будет использовано киберпреступниками для совершения мошенничества, которое может оказаться очень дорогим для тех отвлеченных пользователей. Прекрасным примером является WhatsApp . Каждое новшество, анонсированное службой обмена мгновенными сообщениями, немедленно используется бандитами в сети для развертывания всех видов методов социальной
Верность женщине, или почему женщины реже уходят из соревнования
... позволяет продавцу выделиться из толпы, что также приводит к результатам продаж. Так почему же польские магазины придают так мало значения своему внешнему виду? Ниже я собрал функции, которые должны иметь хороший шаблон аукциона. 1. Соответствие отрасли и продаваемому ассортименту Появление страницы курса должно побудить клиента ознакомиться с предложением. Итак, давайте удостоверимся, что он соответствует диапазону, который мы предлагаем. Особенно
iOS 11.4.1 запрещает доступ полиции к айфонам. Официальный список изменений
Но это фантастическая история. Давайте начнем с самого начала - если у вас есть устройство Apple, возможно, вы только что получили обновление программного обеспечения. Телевизор и часы получили более новые версии систем, которые устраняют ошибки прежде всего. В случае с iPhone или iPad, iOS 11.4.1 также в основном является «исправлением» (особенно это в конце концов iOS 12 это просто правильно).
Intel только что ввела гвоздь в гроб традиционных жестких дисков
... что узнали, как будет выглядеть будущее SSD накопителей. все благодаря конференции Intel и Micron , где представлена ​​подробная информация о новом поколении флеш-памяти под названием 3D NAND. Уже известно, что первое поколение памяти, выполненное по этой технологии, будет представлять собой 32-слойные кости MLC емкостью
Что такое Google Toolbar Notifier и как от него избавиться
Раньше я использовал панель инструментов Google с Firefox и Internet Explorer, потому что у нее были некоторые полезные функции, которые я использовал на регулярной основе, и это позволило мне оставаться подключенным к моей учетной записи Google. Однако это было как десять лет назад. Все на панели инструментов теперь в Google Chrome, и использование IE значительно упало. Тем не менее, если вы застряли в IE или предпочитаете использовать Firefox, панель инструментов Google может быть вам
Что такое спред форекс и как это влияет на инвестирование?
Если вы начинаете приключение с рынка форекс, вы должны быстро понять, что такое спред, как он работает и насколько он важен в торговле. Это один из основных уроков, которые вам нужно сделать, если вы вообще думаете о торговле. Форекс соблазняет потенциальной прибылью, финансовым рычагом и доступом к рынкам со всего мира. Я не удивлен, у меня также есть небольшой спекулятивный счет, и, несмотря на большое участие на фондовом рынке, я проверяю свои навыки

Комментарии

Сколько раз получалось, что у вас есть половина отвержденного лака, который вы больше не можете использовать, потому что вы купили слишком много их, а затем вы положили их в различные тайники?
Сколько раз получалось, что у вас есть половина отвержденного лака, который вы больше не можете использовать, потому что вы купили слишком много их, а затем вы положили их в различные тайники? И оказалось, что у вас есть 6 красных лаков, и ни один из них не пригоден для использования. Ответы на вопрос, как хранить косметику, мы ищем не только для комфорта или порядка, но и для здоровья. Косметика, используемая и хранящаяся неправильно, также представляет риск заболеваний и инфекций.
Но что такое пропеллер с фиксированным шагом или FPP?
Но что такое пропеллер с фиксированным шагом или FPP? Пропеллер спроектирован таким образом, что, если вы отрежете пропеллер в радиальном направлении на любом произвольном радиусе от его центра, то срезанный участок лопастей пропеллера будет иметь определенный шаг (величина зависит от того, насколько он закручен по длине концентратор). Теперь, если вы вращаете этот отрезанный участок в воде, осевое расстояние, пройденное за один оборот, является шагом этого отрезка. Если вы изменяете
Лыжная страховка - что должно содержать комплексную защиту?
Лыжная страховка - что должно содержать комплексную защиту? 1. Страхование медицинских расходов Франция - одна из немногих европейских стран, где лечение полностью оплачивается, если у нас нет надлежащей лыжной политики. Чтобы получить медицинскую помощь, вы должны оплатить счет из собственного кармана. Мы можем подать заявку на их возвращение в местную медицинскую службу только после возвращения домой. Однако мы не должны рассчитывать на получение всей суммы обратно.
Могу ли я изменить цвет и тип обложки после размещения заказа на фотокнигу LUX?
Могу ли я изменить цвет и тип обложки после размещения заказа на фотокнигу LUX? Да, но только если заказ еще не оплачен: 1) На вкладке Мои заказы -> Ваша корзина покупок, которая не была заказана: выбрав добавку и изменив цвет обложки 2) На вкладке Мои заказы -> История заказов выберите Добавить копию в корзину. Проект перейдет на вкладку Мои заказы-> Ваша корзина. Fotokiewczyka / Звездная книга / Фотоальбом Премиум. Преимущества фотокниги
Но что делать, чтобы воспользоваться этим богатством, когда у нас нет компьютера или смартфона с подключением к интернету?
Но что делать, чтобы воспользоваться этим богатством, когда у нас нет компьютера или смартфона с подключением к интернету? Хорошей идеей будет предварительно скачать музыку с YouTube и сохранить ее в виде файла MP3. Как это сделать простым способом вы узнаете из этого поста. Как скачать MP3 с YouTube онлайн? Самый простой способ загрузить файл MP3 с YouTube - это использовать один из веб-сайтов. Мы рекомендуем сервис для этой цели
Разве данные, свидетельствующие о том, что польская электронная коммерция не сильна за рубежом, не являются неожиданностью?
Разве данные, свидетельствующие о том, что польская электронная коммерция не сильна за рубежом, не являются неожиданностью? Польша остается одним из самых быстрорастущих рынков с точки зрения электронной коммерции в Европе - с двузначными темпами роста. Доходы от электронной торговли Польши в первой половине 2018 года составили 8 194 млн. Долларов США. (рост на 10,7 процента по сравнению с 2017 годом), тогда как мировые продажи составили 2,30 триллиона долларов. в 2017
И что делать, если некоторые данные были сохранены?
И что делать, если некоторые данные были сохранены? Вам нужно будет удалить историю поиска. Как удалить историю поиска? Вы уже знаете, что существует такая вещь, как история поиска Google, но вы не хотите, чтобы кто-то другой знал, какую информацию вы искали? Посмотрите, как удалить историю поиска! Если мы не используем учетную запись Google, удалить историю поиска довольно просто. Все, что вам нужно сделать, это очистить историю, включая куки, с помощью программы или
А что, если оно подсвечивает небо так, что вместо облаков на снимке появляется белое пятно?
А что, если оно подсвечивает небо так, что вместо облаков на снимке появляется белое пятно? Все эти вопросы простые советы. Включите режим художественного фильтра и посмотрите, как выглядит отфильтрованный мир в видоискателе. Автор: Яцек Бонецки - путешественник, фотограф, кинематографист, телепродюсер и журналист. Прекрасно находит себя в различных областях фотографии, таких как фотосъемка в путешествиях, спорт, реклама, автомобильная и репортажная фотография.
Момент, когда вы поняли, что многие ваши коллеги интересны?
Момент, когда вы поняли, что многие ваши коллеги интересны? Помните ли вы свое первое влюбление, когда вы оказались в дыре, когда увидели другого человека, и ваше сердце билось как сумасшедший? Эти моменты являются первыми признаками сексуальной химии. «Даже когда прошли годы с первых юношеских немощей, сексуальная химия для нас это остается такой же загадкой, как и раньше. Во-первых, очень трудно определить это,
Для линейных альянсов есть много позитива, но что хорошего из них получается для нас или путешественников?
Для линейных альянсов есть много позитива, но что хорошего из них получается для нас или путешественников? Несомненным преимуществом является возможность использования большего количества соединений и соединений, чем одного оператора. Проще говоря, вы можете планировать поездку на основе почти всей сети соединений альянса ... с одним билетом и одним посадочным талоном. Давайте посмотрим на конкретный пример. Вы хотите добраться из Польши в Сиэтл в США в середине апреля.
Что вы думаете о цифровой манге или комиксах?
Что вы думаете о цифровой манге или комиксах? Считаете ли вы это приемлемым вариантом? Или ты придерживаешься физической версии? Дайте мне знать в разделе комментариев ниже. Дальнейшие ссылки

Что случилось с нашей строкой JSON {a: 'a', b: 'b'}?
Что такое раздел восстановления?
Что такое раздел, какую функцию он выполняет, для чего он может быть полезен?
Ты помнишь первого мальчика, который тебе понравился?
Момент, когда вы поняли, что многие ваши коллеги интересны?
Помните ли вы свое первое влюбление, когда вы оказались в дыре, когда увидели другого человека, и ваше сердце билось как сумасшедший?
Обы оно соответствовало действующим правилам?
Обы оно соответствовало действующим правилам?
Планшет - купить с Wi-Fi или 3G?