Строгая типизация в php

Содержание:

Типовая дисперсия и наследование

Несмотря на то, что в PHP 7.4 появилась улучшенная дисперсия типов, типизированные свойства все еще остаются неизменными. Это означает, что следующий код будет не валиден:

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

PHP за кадром заменит self на конкретный класс, на который он ссылается, перед запуском кода. Это означает, что в этом примере будет сгенерирована та же ошибка. Единственный способ справиться с этим — сделать следующее:

Говоря о наследовании, вам может быть трудно найти какие-либо хорошие варианты использования для перезаписи типов унаследованных свойств.

Хотя я согласен с этим мнением, стоит отметить, что можно изменить тип унаследованного свойства, но только если модификатор доступа также изменится с private на protected или public:

Однако изменение типа с обнуляемого на ненулевое или обратное не допускается.

Оператор безопасного null (Nullsafe operator)

Null — сам по себе не очень хорошая штука (даже очень плохая). Когда функция возвращает , то в каждом месте, где идёт её вызов, программист обязан проверить на . И это приводит к ужасным последствиям.

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

Более правильный вариант:

Интересным моментом в использовании nullsafe есть то, что при вызове метода с помощью , параметры будут обработаны только если объект не :

Оператор ––>

также известен как «оператор супер-объекта», создан на основе своего дальнего двоюродного брата, .

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

Оператор «стрелки влево» для массивов

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

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

PHP статическое ключевое слово

Обычно, когда функция завершается/выполняется, все ее переменные удаляются.
Однако иногда мы хотим, чтобы локальная переменная не была удалена. Мы нуждаемся в ней для дальнейшей работы.

Для этого используйте ключевое слово при первом объявлении переменной:

Пример

<?phpfunction myTest()
{
    static $x = 0;
    echo $x;
    $x++;
}
myTest();
myTest();
myTest();?>

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

Примечание: Переменная по-прежнему является локальной для функции.

❮ Назад
Дальше ❯

Вычисляем расстояние между двумя точками

Следующая функция предназначена для вычисления расстояния между двумя точками, в зависимости от их координат.

function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2) {
    $theta = $longitude1 - $longitude2;
    $miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
    $miles = acos($miles);
    $miles = rad2deg($miles);
    $miles = $miles * 60 * 1.1515;
    $feet = $miles * 5280;
    $yards = $feet / 3;
    $kilometers = $miles * 1.609344;
    $meters = $kilometers * 1000;
    return compact('miles','feet','yards','kilometers','meters');
}

Пример:

$point1 = array('lat' => 40.770623, 'long' => -73.964367);
$point2 = array('lat' => 40.758224, 'long' => -73.917404);
$distance = getDistanceBetweenPointsNew($point1, $point1, $point2, $point2);
foreach ($distance as $unit => $value) {
    echo $unit.': '.number_format($value,4).'<br />';
}

Определяем язык браузера

Если вы создаёте многоязычный сайт, то неплохо было бы знать язык браузера и, в зависимости от этого, отобразить сайт в том или ином виде.

function get_client_language($availableLanguages, $default='en'){
	if (isset($_SERVER)) {
		$langs=explode(',',$_SERVER);

		foreach ($langs as $value){
			$choice=substr($value,0,2);
			if(in_array($choice, $availableLanguages)){
				return $choice;
			}
		}
	}
	return $default;
}

Получаем размер файла

Для получения размера файла можете воспользоваться следующей функцией:

<?php
function file_size($url){
    $size = filesize($url);
    if($size >= 1073741824){
        $fileSize = round($size/1024/1024/1024,1) . 'GB';
    }elseif($size >= 1048576){
        $fileSize = round($size/1024/1024,1) . 'MB';
    }elseif($size >= 1024){
        $fileSize = round($size/1024,1) . 'KB';
    }else{
        $fileSize = $size . ' bytes';
    }
    return $fileSize;
}
echo file_size('/myfile/image.jpg');
?>

Sniffing your code for compatibility with specific PHP version(s)

  • Run the coding standard from the command-line with .
  • By default, you will only receive notifications about deprecated and/or removed PHP features.
  • To get the most out of the PHPCompatibility standard, you should specify a to check against. That will enable the checks for both deprecated/removed PHP features as well as the detection of code using new PHP features.
    • You can run the checks for just one specific PHP version by adding to your command line command.
    • You can also specify a range of PHP versions that your code needs to support. In this situation, compatibility issues that affect any of the PHP versions in that range will be reported: .
    • As of PHPCompatibility 7.1.3, you can omit one part of the range if you want to support everything above or below a particular version, i.e. use to run all the checks for PHP 7.0 and above.
  • By default the report will be sent to the console, if you want to save the report to a file, add the following to the command line command: .
    For more information and other reporting options, check the PHP CodeSniffer wiki.

Using a framework/CMS/polyfill specific ruleset

As of mid 2018, a limited set of framework/CMS specific rulesets is available. These rulesets are hosted in their own repositories.

Since the autumn of 2018, there are also a number of PHP polyfill specific rulesets available:

IMPORTANT: Framework/CMS/Polyfill specific rulesets do not set the minimum PHP version for your project, so you will still need to pass a to get the most accurate results.

* * *

На мой взгляд, такое решение — дженерики. Не буду подробно расписывать, что они делают, об этом вы можете почитать в RFC. Но я приведу пример того, как дженерики могут помочь в решении вышеописанных проблем, всегда обеспечивая наличие в коллекции корректных данных.

Важное замечание: дженериков пока что нет в PHP. RFC предназначен для PHP 7.1, о его будущем нет никакой дополнительной информации

Нижеприведённый код основан на интерфейсах Iterator и ArrayAccess, которые существуют с PHP 5.0. В конце мы разберём пример с дженериками, представляющий собой фиктивный код.

Для начала создадим класс , который работает в PHP 5.0+. Этот класс реализует , чтобы можно было циклически проходить по его элементам, а также , чтобы можно было использовать «массивоподобный» синтаксис для добавления элементов коллекции и обращения к ним.

Теперь можем воспользоваться подобным классом:

Обратите внимание: нет никакой гарантии, что содержит только. Если добавить, к примеру, строковое значение, то работать будет, но наш цикл сломается

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

Обратите внимание: типы возвращаемых данных, допускающие использование null, доступны лишь с PHP 7.1

Теперь в нашу коллекцию могут добавляться только .

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

Вероятно, создавать подклассы можно с бо́льшим удобством, «злоупотребив» поздним статическим связыванием и рефлексивным API PHP. Но вам в любом случае понадобится создавать классы для каждого доступного типа.

Проверка типа

Во время выполнения программы иногда возникает необходимость узнать, к какому типу относится то или иное значение

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

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

Функции проверки типа
Функция Описание
gettype(arg) Возвращает строку, представляющую тип arg: integer (целое число), float (число с плавающей точкой), string (строковое значение), array (массив), object (объект) или unknown (неизвестный тип)
is_int(arg), is_integer(arg), is_long(arg) Возвращает значение true, если arg — целое число, в противном случае — false
is_double(arg), is_float(arg), is_real(arg) Возвращает значение true, если arg — число с плавающей точкой, в противном случае — false
is_bool(arg) Возвращает значение true, если arg — булево значение (true или false), в противном случае — false
is_null(arg) Возвращает значение true, если arg имеет тип null, в противном случае — false
is_string(arg) Возвращает значение true, если arg — строка, в противном случае — false
is_array(arg) Возвращает значение true, если arg — массив, в противном случае — false
is_object(arg) Возвращает значение true, если arg — объект, в противном случае — false
is_resource(arg) Возвращает значение true, если arg — ресурс, в противном случае — false
is_binary(arg) Возвращает значение true, если arg — двоичная строка, в противном случае — false
is_buffer(arg) Возвращает значение true, если arg — строка в Юникоде или двоичная строка, в противном случае — false
is_scalar(arg) Возвращает значение true, если arg — скалярная переменная, в противном случае — false
is_unicode(arg) Возвращает значение true, если arg — строка в Юникоде, в противном случае — false
is_numeric(arg) Возвращает значение true, если arg — числовое значение, в противном случае — false

Типы типов

Я уже упоминал, что типизированные свойства будут работать только в классах (пока), и что им нужен модификатор доступа или ключевое слово var перед ними.

Что касается доступных типов, то могут использоваться почти все типы, кроме void и callable.

Поскольку void означает отсутствие значения, имеет смысл, что его нельзя использовать для ввода значения. А вот с callable есть небольшой нюанс.

Callable в PHP может быть написан так:

Скажем, у вас будет следующий (неработающий) код:

В этом примере $callable относится к частному Bar::method, но вызывается в контексте Foo. Из-за этой проблемы и было решено не добавлять callable в список поддерживаемых типов.

Это не имеет большого значения, потому что замыкания (Closure) это допустимый тип, который будет помнить контекст $this, в котором он был создан.

С учетом всего написанного, вот список всех доступных типов:

  • bool (логический)
  • int (целый)
  • float (вещественный)
  • string (строковый)
  • array (массив)
  • iterable (псевдотип)
  • object (объект)
  • ? (nullable)
  • self (объект того же тип)
  • classes (классы)

Автоматизация Instagram

Из песочницы

По работе попалась интересная задача по автоматизации Instagram, а именно надо было просто провести розыгрыш. Сервисов для организации этой затеи достаточно, есть даже бесплатные. Но были дополнительные (читай премиум) условия, к тому же мне очень захотелось самому посмотреть, что там внутри этой популярной инстаграмы и быть может набраться опыта в построении API.

Первым делом пошел смотреть что там говорят интернеты. Чтение официальных доков по API instagram дали четко понять, что владельцы не хотят давать доступ к неограниченной автоматизации, можно автоматизировать работу со своим аккаунтом в базовом варианте, но это не подходило под мою задачу, а «бизнес» вариант API требовал верификации компании, что естественно мне не подходит. (Может быть уже что-то изменилось …)

Тайп хинтинги

Для начала давайте разберемся, для чего вообще нужны тайпхинтинги в php, чтобы ни у кого не осталось вопросов а ля «зачем эта лишняя писанина».

Немного отвлечемся и посмотрим кусок кода на javascript:

Что мы можем сказать об этой функции? Она берет каких-то пользователей и фильтрует их по возрасту. Но этого мало, потому что сразу возникают вопросы:

Что такое users? Массив? Или какой-то хитрый объект-коллекция?
Возраст задан как целое число или может быть дробным?
Может ли возраст быть null?
Возвращает ли эта фунция значение или же меняет переданный массив users?

Чтобы всё это понять, надо прочесть код функции, а также вызовы этой функции. Ошибки будет отловить сложно, потому что язык не будет ругаться ни на какие аргументы, а будет пытаться их как-то привести к нужному типу.

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

Для сравнения код на последних версиях php:

Тут мы видим, что на входе массив пользователей, возраст может быть null, возвращается также массив. Гораздо яснее, не так ли? Если же в нужных местах указать , то при попытке пихнуть дробное число в качестве возраста, мы получим ошибку.

Вроде всё супер, но есть нюансы.

Создание (объявление) переменных PHP

В PHP переменная начинается с знака $, за которым следует имя переменной:

Пример

<?php
$txt = «Hello world!»;
$x = 5;$y = 10.5;
?>

После выполнения вышеприведенных инструкций переменная $txt будет удерживать значение Hello World!, переменная $x будет удерживать значение 5, а переменная $y будет удерживать значение 10,5.

Примечание: При назначении переменной текстового значения поместите кавычки вокруг значения.

Примечание: В отличие от других языков программирования, PHP не имеет команды для объявления переменной. Он создается в момент, когда вы сначала присваиваете ему значение.

Представьте переменные как контейнеры для хранения данных.

⚠️ Upgrading to PHPCompatibility 9.0.0 ⚠️

This library has been reorganized. All sniffs have been placed in categories and a significant number of sniffs have been renamed.

If you use the complete standard without directives in a custom ruleset and do not (yet) use the new-style PHP_CodeSniffer annotation as introduced in PHP_CodeSniffer 3.2.0, this will have no noticeable effect and everything should work as before.

However, if you do use directives for PHPCompatibility sniffs in a custom ruleset or if you use the new-style PHP_CodeSniffer inline annotations, you will need to update these when upgrading. This should be a one-time only change.
The changelog contains detailed information about all the sniff renames.

Please read the changelog for version 9.0.0 carefully before upgrading.

Инспекции кода в PHPStorm

deep-assoc-completion

Место анализаторов в нашем QA

  • мы используем несколько видов автотестов;
  • у нас есть code review;
  • у нас есть ручное тестирование.
  • они могут покрыть 100% кода (в отличие от тестов, которые для каждого участка кода надо писать отдельно);
  • они часто отлавливают такие ошибки, которые сложно заметить в процессе code review;
  • они способны анализировать даже тот код, который сложно или невозможно запустить при ручном тестировании.
  • анализаторы работают для всего кода, а чтобы увидеть ошибки , нужно исполнить код;
  • ошибку анализатора можно исправить позже, если она не критична (возможно, это не лучшая практика, но в некоторых случаях это может быть полезно);
  • система типов в статических анализаторах даже более гибкая, чем в самом PHP (например, они поддерживают , которых нет в PHP);
  • статические анализаторы приближают нас к внедрению , поскольку они умеют эмулировать такие же строгие проверки.

Объединения типов (Union Types 2.0)

Рассмотрим код:

Здесь тип переменной контролируется только соглашениями программистов. На самом деле, туда может попасть что-угодно, и выйти отсюда может также что-угодно, так как проверки на тип не обеспечиваются ядром языка.

Теперь же, можно прописать тип (или любой другой) явно, чтобы обеспечить корректность работы модуля:

А также, код становится немного чище, так как мы можем избавится от излишних комментариев.

Типы-объединения имеют синтаксис и могут быть использованы во всех местах, где можно прописать type-hints с некоторыми оговорками:

  • Тип не может быть частью объединения.
  • Чтобы обозначить отсутствие результата, можно объявить «Nullable union type», который имеет следующий синтаксис: .
  • Тип не может быть использован вне объединения. Вместо него стоит использовать .
  • Существует также псевдотип , который по историческим причинам уже используется некоторыми функциями в php. С другой стороны, не существует тип , так как он нигде не использовался ранее.

Типы полей класса инвариантны, и не могут быть изменены при наследовании.
А вот с методами всё немного интересней:

  1. Параметры методов можно расширить, но нельзя сузить.
  2. Возвращаемые типы можно сузить, но нельзя расширить.

Вот как это выглядит в коде:

То же самое происходит при типах, которые получились как результат наследования:

Интереснее становится когда установлен в , то-есть по-умолчанию. Например, функция принимает , а мы передали ей . Что в результате должно быть в переменной? Пустая строка, или ноль? Есть набор правил, по которым будет производиться приведение типов.

Так, если переданный тип не является частью объединения, то действуют следующие приоритеты:

  1. int;
  2. float;
  3. string;
  4. bool;

Так вот, будет перебираться этот список с типами, и для каждого проверяться: Если тип существует в объединении, и значение может быть приведёно к нему в соответствии с семантикой PHP, то так и будет сделано. Иначе пробуем следующий тип.

Как исключение, если должен быть приведён к , то сравнение идёт в первую очередь в соответствии с семантикой «числовых строк». К примеру, станет , в то время как станет .

Таблица неявного приведения типов:

Original type 1st try 2nd try 3rd try

Типы полей и ссылки

Здесь проблема в том, что тип устанавливаемого значения не совместим с объявленными в полях класса. Для — это могло быть , а для — . Так как эти значения не эквивалентны, то невозможно обеспечить единую ссылку, и будет сгенерирован.

Значения по умолчанию и конструкторы

Давайте подробнее рассмотрим, как можно инициализировать типизированные значения. В случае скалярных типов можно указать значение по умолчанию:

Вы можете использовать null по умолчанию, только если тип на самом деле обнуляем. Это может показаться очевидным, но есть некоторое устаревшее поведение с параметрами по умолчанию, где допускается следующее:

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

Также обратите внимание, что невозможно иметь значения по умолчанию с object типами или классами. Вы должны использовать конструктор, чтобы установить их значения по умолчанию

Очевидным местом для инициализации типизированных значений, конечно же, будет конструктор:

Но также помните, что я упоминал ранее: допустимо писать в неинициализированное свойство вне конструктора. Пока из свойства ничего не читается, неинициализированная проверка не выполняется.

Сравним C++, JS, Python, Python + numba, PHP7, PHP8, и Golang на примере расчёта “Простое Число”

Все топовые языки программирования уже давно доказали свои позиции и «определились» с нишами своего использования.

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

Измерять можно довольно много параметров и для разных целей.

Для каких-то задач важнее будет наличие быстрого просчёта по математическим операциям. А для других — больше пригодится ускоренная работа с сетью и файлами.

В данной статье мы рассмотрим ускорение программы с использованием JIT-компиляции для языков Python и PHP.

В качестве задачи для расчёта возьмём функцию проверки — является ли число Простыми или нет — «is prime». Возьмём базовый алгоритм проверки на то, что число Простое:

PHP 7.0

Анонимный класс может использоваться вместо именованного класса:

Когда класс не нужно документировать

Когда класс во время выполнения используется только один раз

Функция целочисленного деления — безопасный способ деления (даже на 0).

Возвращает целочисленный результат деления первого операнда на второй. Если делитель (второй операнд) равен нулю, функция пробрасывает EWARNING и возвращает FALSE.

Добавлен новый оператор объединения с null — «??»

Добавлен новый оператор — spaceship (космический корабль) (<=>)

Используется для оптимизации и упрощения операций сравнения.

Это всего лишь первый шаг к реализации преимуществ более строго типизированного языка программирования в PHP — v0.5.

Добавлена ​​возможность возвращать типы помимо скалярных — классы, включая наследование. Хех, упустив при этом возможность сделать это необязательным (что будет введено в v7.1 :))

Групповые объявления use

В теле функций генераторов разрешен следующий новый синтаксис:

PHP 7 почти вдвое быстрее, чем PHP 5.6.

Значительное сокращение использования памяти

Как видно из диаграмм, PHP 7.0 стал громадным шагом вперед с точки зрения производительности и использования памяти. Для страницы с запросами к базе данных версия 7.0.0 более чем в 3 раза быстрее, чем 5.6 с включенным opcache в 2.7 раза быстрее без opcache! С точки зрения использования памяти разница тоже существенная!

Классы исключений были реструктурированы к более контринтуитивной схеме именования, которая приведет к меньшей путанице, особенно для новых пользователей.

и теперь реализуют .

Иерархия :

Внимание! Вы можете реализовать только через и. Синтаксис кодирования Unicode — “\u{xxxxx}”

Синтаксис кодирования Unicode — “\u{xxxxx}”

С этим нововведением глобально зарезервированные слова стали полу-зарезервированными:

За исключением того, что по-прежнему запрещено определять константу класса с именем из-за разрешения имени класса .

Глобальная и локальная область

Переменная, объявленная вне функции, имеет глобальную область видимости и может быть доступна только за пределами функции:

Пример

<?php$x = 5; // global scopefunction myTest() {    // using x inside this function will generate an error    echo «<p>Variable x inside function is: $x</p>»;} myTest();echo «<p>Variable x outside function is: $x</p>»;?>

Переменная, объявленная внутри функции, имеет локальную область видимости и доступна только в этой функции:

Пример

<?phpfunction myTest() {    $x = 5; // local scope    echo «<p>Variable x inside function is: $x</p>»;} myTest();// using x outside the function will generate an errorecho «<p>Variable x outside function is: $x</p>»;?>

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

Неинициализированный тип состояния

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

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

Даже если значение $bar не является целым числом после создания объекта Foo, PHP будет выдавать ошибку только при обращении к $bar:

Как можно заметить из сообщения об ошибке, существует новый тип «состояния переменной»: неинициализированный.

Если бы у $bar не было типа, его значение было бы просто null. Однако типы могут быть обнуляемыми, поэтому невозможно определить, было ли установлено типизированное свойство обнуляемого типа или просто забыто. Вот почему было добавлено «неинициализированное» состояние.

Есть четыре важных момента, которые нужно помнить о неинициализированных состояниях:

  • Вы не можете считать значение из неинициализированных свойств, это приведет к фатальной ошибке.
  • Поскольку при обращении к свойству проверяется неинициализированное состояние, вы можете создать объект с неинициализированным свойством, даже если его тип не имеет значения NULL.
  • Вы можете написать неинициализированное свойство перед чтением из него.
  • Использование unset в типизированном свойстве сделает его неинициализированным, в то время как отключение нетипизированного свойства сделает его null.

Особенно обратите внимание, что следующий код, где неинициализируемое, ненулевое свойство устанавливается после создания объекта, является рабочим:

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

Отправка логов ошибок себе на email

<?php

function nettuts_error_handler($number, $message, $file, $line, $vars){
	$email = "
		<p>An error ($number) occurred on line
		<strong>$line</strong> and in the <strong>file: $file.</strong>
		<p> $message </p>";

	$email .= "<pre>" . print_r($vars, 1) . "</pre>";

	$headers = 'Content-type: text/html; charset=utf-8' . "\r\n";

	// отправка email-а
	error_log($email, 1, 'you@youremail.com', $headers);

	// останавливаем скрипт при возникновении ошибки
	// если она не NOTICE.
	if ( ($number !== E_NOTICE) && ($number < 2048) ) {
		die("There was an error. Please try again later.");
	}
}

// назначаем собственный обработчик.
set_error_handler('nettuts_error_handler');

// генерируем ошибку... (переменной не существует)
echo $somevarthatdoesnotexist;

Using a custom ruleset

Like with any PHP CodeSniffer standard, you can add PHPCompatibility to a custom PHP CodeSniffer ruleset.

<?xml version="1.0"?>
<ruleset name="Custom ruleset">
    <description>My rules for PHP CodeSniffer</description>

    <!-- Run against the PHPCompatibility ruleset -->
    <rule ref="PHPCompatibility"/>

    <!-- Run against a second ruleset -->
    <rule ref="PSR2"/>

</ruleset>

You can also set the from within the ruleset:

    <!-- Check for cross-version support for PHP 5.6 and higher. -->
    <config name="testVersion" value="5.6-"/>

Other advanced options, such as changing the message type or severity of select sniffs, as described in the PHPCS Annotated ruleset wiki page are, of course, also supported.

in the ruleset versus command-line

In PHPCS 3.2.0 and lower, once you set the in the ruleset, you could not overrule it from the command-line anymore.
Starting with PHPCS 3.3.0, a set via the command-line will overrule the in the ruleset.

This allows for more flexibility when, for instance, your project needs to comply with PHP , but you have a bootstrap file which needs to be compatible with PHP .

PHPCompatibility specific options

At this moment, there is one sniff which has a property which can be set via the ruleset. More custom properties may become available in the future.

The sniff checks for removed extensions based on the function prefix used for these extensions.
This might clash with userland functions using the same function prefix.

To whitelist userland functions, you can pass a comma-delimited list of function names to the sniff.

    <!-- Whitelist the mysql_to_rfc3339() and mysql_another_function() functions. -->
    <rule ref="PHPCompatibility.Extensions.RemovedExtensions">
        <properties>
            <property name="functionWhitelist" type="array" value="mysql_to_rfc3339,mysql_another_function"/>
        </properties>
    </rule>

Requirements

  • PHP 5.4+
  • PHP CodeSniffer: 2.6.0+ or 3.1.0+.

The sniffs are designed to give the same results regardless of which PHP version you are using to run PHP CodeSniffer. You should get consistent results independently of the PHP version used in your test environment, though for the best results it is recommended to run the sniffs on a recent PHP version in combination with a recent PHP_CodeSniffer version.

For running the sniffs on PHP 7.3, it is recommended to use PHP_CodeSniffer 3.3.1+, or, if needs be, PHP_CodeSniffer 2.9.2.
PHP_CodeSniffer < 2.9.2/3.3.1 is not fully compatible with PHP 7.3, which effectively means that PHPCompatibility can’t be either.
While the sniffs will still work in most cases, you can expect PHP warnings to be thrown.

For running the sniffs on PHP 7.4, it is recommended to use PHP_CodeSniffer 3.5.0+ for the same reasons.

As of version 8.0.0, the PHPCompatibility standard can also be used with PHP CodeSniffer 3.x.
As of version 9.0.0, support for PHP CodeSniffer 1.5.x and low 2.x versions < 2.3.0 has been dropped.
As of version 10.0.0, support for PHP < 5.4 and PHP CodeSniffer < 2.6.0 has been dropped.

Installation in a Composer project (method 1)

  • Add the following lines to the section of your file.
    "require-dev": {
        "phpcompatibility/php-compatibility": "*"
    },
    "prefer-stable" : true
  • Next, PHP CodeSniffer has to be informed of the location of the standard.
    • If PHPCompatibility is the only external PHP CodeSniffer standard you use, you can add the following to your file to automatically run the necessary command:

      "scripts": {
          "post-install-cmd": "\"vendor/bin/phpcs\" --config-set installed_paths vendor/phpcompatibility/php-compatibility",
          "post-update-cmd" : "\"vendor/bin/phpcs\" --config-set installed_paths vendor/phpcompatibility/php-compatibility"
      }
    • Alternatively — and strongly recommended if you use more than one external PHP CodeSniffer standard — you can use any of the following Composer plugins to handle this for you.

      Just add the Composer plugin you prefer to the section of your file.

      • DealerDirect/phpcodesniffer-composer-installer:»^0.6.0″
      • higidi/composer-phpcodesniffer-standards-plugin
      • SimplyAdmire/ComposerPlugins. This plugin might still work, but appears to be abandoned.
    • As a last alternative in case you use a custom ruleset, and only if you use PHP CodeSniffer version 2.6.0 or higher, you can tell PHP CodeSniffer the path to the PHPCompatibility standard by adding the following snippet to your custom ruleset:

      <config name="installed_paths" value="vendor/phpcompatibility/php-compatibility" />
  • Run to install both PHP CodeSniffer, the PHPCompatibility coding standard and — optionally — the Composer plugin.
  • Verify that the PHPCompatibility standard is registered correctly by running on the command line. PHPCompatibility should be listed as one of the available standards.
  • Now you can use the following command to inspect your code:
    ./vendor/bin/phpcs -p . --standard=PHPCompatibility

Операторы сравнения PHP

Операторы сравнения PHP используются для сравнения двух значений (число или строка):

Оператор Имя Пример Результат Запуск
== Equal $x == $y Возвращает значение true, если $x равно $y
=== Identical $x === $y Возвращает значение true, если $x равно $y, и они имеют одинаковый тип
!= Not equal $x != $y Возвращает значение true, если $x не равно $y
<> Not equal $x <> $y Возвращает значение true, если $x не равно $y
!== Not identical $x !== $y Возвращает значение true, если $x не равно $y, или они не одного типа
> Greater than $x > $y Возвращает значение true, если $x больше $y
< Less than $x < $y Возвращает значение true, если $x меньше $y
>= Greater than or equal to $x >= $y Возвращает значение true, если $x больше или равно $y
<= Less than or equal to $x <= $y Возвращает значение true, если $x меньше или равно $y

Извлечение всех твитов по специальному хэштегу

Лёгкий способ извлечения твитов по хэштегу с помощью расширения cURL. В следующем примере используем хэштег #cat:

function getTweets($hash_tag) {

    $url = 'http://search.twitter.com/search.atom?q='.urlencode($hash_tag) ;
    echo "<p>Connecting to <strong>$url</strong> ...</p>";
    $ch = curl_init($url);
    curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);
    $xml = curl_exec ($ch);
    curl_close ($ch);

    $affected = 0;
    $twelement = new SimpleXMLElement($xml);
    foreach ($twelement->entry as $entry) {
        $text = trim($entry->title);
        $author = trim($entry->author->name);
        $time = strtotime($entry->published);
        $id = $entry->id;
        echo "<p>Tweet from ".$author.": <strong>".$text."</strong>  <em>Posted ".date('n/j/y g:i a',$time)."</em></p>";
    }

    return true ;
}

getTweets('#cats');

Целостность структуры данных (Data integrity)

В PHP массив представляет собой коллекцию элементов.

Если циклически пройти по нашему набору постов, то в результате получим критическую ошибку.

Вызываем применительно к строке . Не прокатило. При циклическом проходе по массиву мы хотим быть уверены, что все значения принадлежат к определённому типу. Можно сделать так:

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

С целостностью структуры данных есть ещё одна сложность. Допустим, у вас есть метод, которому нужен массив блог-постов:

Мы опять можем добавить в цикл дополнительные проверки, но это не гарантирует, что содержит только коллекцию постов Posts.

для решения этой проблемы вы можете использовать оператор :

Но у этого подхода есть обратная сторона: вам придётся вызывать функцию применительно к распакованному массиву.

Загрузка и сохранение изображения на ваш сервер

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

$image = file_get_contents('http://www.url.com/image.jpg');
file_put_contents('/images/image.jpg', $image); //сохраняем изображение на вашем сервере

Создание data uri

Через data uri мы можем преобразовывать такие элементы, как html/css/js, для уменьшения http запросов к сторонним ресурсам. Вот, как мы можем это сделать через PHP:

function data_uri($file, $mime) {
  $contents=file_get_contents($file);
  $base64=base64_encode($contents);
  echo "data:$mime;base64,$base64";
}

PHPStan

  1. Установить его (проще всего это сделать через Composer).
  2. (опционально) Сконфигурировать.
  3. В простейшем случае достаточно запустить:
  1. Можно анализировать не всю кодовую базу, а только часть — неизвестные классы PHPStan попытается подгрузить автолоадом.
  2. Если по какой-то причине какие-то ваши классы не в автолоаде, PHPStan не сможет их найти и выдаст ошибку.
  3. Если у вас активно используется магические методы через , то вы можете написать плагин для PHPStan. Уже существуют плагины для Symfony, Doctrine, Laravel, Mockery  и др.
  4. На самом деле, PHPStan выполняет автолоад не только для неизвестных классов, а вообще для всех. У нас много старого кода, написанного до появления анонимных классов, когда мы в одном файле создаём некий класс, а потом сразу его инстанцируем и, возможно, даже вызываем какие-то методы. Автолоад () таких файлов приводит к ошибкам, потому что код выполняется не в обычном окружении.
  5. Конфиги в формате neon (никогда не слышал, чтобы где-нибудь ещё использовался такой формат).
  6. Нет поддержки своих PHPDoc-тегов типа и т. п.

все

  • Если надо проверить несколько файлов, PHPStan заметно быстрее Phan и немного (на 20—50%) быстрее Psalm.
  • Отчёты PHPStan позволяют нам проще находить в других анализаторах. Обычно, если в коде есть какой-то явный , он показывается всеми анализаторами (или как минимум двумя из трёх).

Update:подсказалhttps://phpstan.org/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector