Никогда не используйте NULL

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

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

Для чего это используется

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

class SomeLoggingService {
    private $logger = null;

    public function setLogger(Logger $logger) {
        $this->logger = $logger;
    }
}

 

В большинстве случаев logger будет установлен, но кто-то забудет об этом при использовании вашего сервиса. На сцену выходит второй разработчик и пишет новый метод в этом классе, используя свойство $logger. Во время разработки свойство всегда устанавливается и тестируется по соответствующим сценариям использования, так что разработчики забывают проверять на null – очевидно, это станет проблемой при других обстоятельствах. Вы полагаетесь на то, что методы будут вызваны в определённом порядке, который сложно документировать. Метод getLogger(), создающий нулевой логгер по умолчанию, мог бы решить эту проблему, но не гарантировано, поскольку второй разработчик может не знать об этом методе и просто использовать свойство.

Читать дальше…

Суперскоростной Symfony с помощью nginx

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

Фреймворки, такие как Symfony, потенциально позволяют создавать суперскоростные приложения. Мы уже видели один способ как добиться этого (путём превращения приложения в HTTP сервер), другой способ заключается в установке обратного прокси перед ним.

В данной статье мы возьмём Symfony приложение и увидим, как увеличить его производительность в 140 раз с помощью nginx.

Читать дальше…

Почему PHP-разработчики думают, что MVC – это архитектура приложения?

Ранее я указывал на то, что Model-View-Controller представляет собой паттерн пользовательского интерфейса, а не архитектуру приложения. Но откуда у PHP-разработчиков возникла идея, что MVC – это в первую очередь архитектура? (Это можно сказать обо всех разработчиках серверной части, не только о PHP)

Я одно время думал, что MVC — это архитектура. Даже после прочтения «Каталога шаблонов корпоративных приложений» Фаулера и, несмотря на то, что MVC предназначался для пользовательского интерфейса, я полагал, что всё правильно понял и делаю «приложение пользовательского интерфейса». Но это было не совсем так; правильнее было бы сказать, что я смешивал проблемы пользовательского интерфейса с основой ядра приложения.

Читать дальше…

Асинхронные контроллеры в Symfony

Асинхронное программирование в последние годы стало синонимом высокой производительности в веб-приложениях со стороны сервера. Во многом это связано с возрастающей популярностью изначально асинхронных JavaScript и Node.js.

Как и многие другие вещи, асинхронное программирование не является чем-то новым. Вы можете использовать этот стиль программирования во многих средах, начиная с Python и заканчивая .NET.

В браузере отдельные события, такие как клик мыши, помещаются в цикл обработки событий (см. What the heck is the event loop anyway?, Филип Робертс), а затем события обрабатываются асинхронно без определённой очерёдности: нельзя точно узнать, когда событие клика мыши выполнится.

Ключевое место в асинхронности занимает I/O. В браузерах данное понятие включено начиная с Internet Explorer 5.0 и популяризировано Gmail в 2004 году. Придуманный метод, AJAX, позволил браузерам выполнять запросы к серверу после первоначальной загрузки страницы.

На сервере неблокирующий асинхронный I/O позволяет, например, продолжать выполнять другие задачи, вместо того, чтобы ожидать выполнения долгих запросов к базе данных. Существует много механизмов для обработки потоков асинхронного кода, такие как фьючерсы/promises, генераторы и наблюдатели.

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

Асинхронный PHP

Читать дальше…

Защищённые классы

Сегодня у меня была любопытная беседа с Дэвидом Мюрреем об идее защищённых моделей от использования в нежелательных контекстах. Он разрабатывал приложение, у которого есть репозитории, работающие с моделями, и мы подумали, что стоит попробовать защитить модели от непосредственного использования.

Ограничения

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

Давайте предположим, что конкретные классы могут быть созданы только в контексте других классов. Мы можем создать только модели Doctrine в репозиториях доктрины, модели Eloquent в Eloquent репозиториях и так далее.

Читать дальше…

Доступ к protected свойствам объектов с общим предком

На днях я понял нечто странное о доступе к protected свойствам. В PHP возможно получить доступ к protected свойствам из других объектов, пока они того же класса, как проиллюстрировано ниже:


<?php

class MyClass 
{
    protected $val;

    public function __construct($newVal = 'default') 
    {
        $this->val = $newVal;
    }

    public function output(MyClass $subject) 
    {
        echo $subject->val, "\n";
    }
}

$obj1 = new MyClass();
$obj2 = new MyClass("hello world");

$obj1->output($obj2);
// Output: hello world

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

Такое поведение работает на свойствах и методах даже тогда, когда область видимость их определяются как private.

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

Звучит немного сложно, так что вот пример:

Читать дальше…

Случайности в PHP 7 – ощущаете ли себя удачливым?

1444736085dice

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

Итак, что такое CSPRNG?

Цитируя Википедию, Криптографически стойкий генератор псевдослучайных чисел (Cryptographically Secure Pseudorandom Number Generator) — это генератор псевдослучайных чисел со свойствами, делающими его подходящим для использования в криптографии.

CSPRNG в основном полезен для:

Читать дальше…

Переходим на PHP 7

php7-logo

Все те, кто слышал, что 12-го ноября выходит PHP 7, могут задаваться вопросами, чего ожидать и как подготовиться. Были внесены действительно большие улучшения языка в ядре и много новых интересных функций. Есть даже слухи и тесты о том, что PHP 7 будет примерно в два раза быстрее, чем PHP 5!

Давайте более подробно рассмотрим, что изменится.

Читать дальше…

Уменьшаем связанность пакетов

2015-10-27_120755

Существуют не так много вариантов того, как мы можем разъединить пакеты, к тому же сделать это не так-то просто. Поэтому давайте рассмотрим, какие варианты лучше других.

Для примера скажем, что вы пишите пакет или библиотеку для ответа на HTTP запросы (такой пакет можно было бы считать базой веб-фреймворка). Как вы справитесь с маршрутизацией?

Если вы напишите свой пакет Router независимым (и он будет хорош: маленькие и специализированные пакеты более универсальны и сопровождаемы), вы бы не хотели связывать его с HTTP пакетом, оставив выбор маршрутизатора на усмотрение пользователя.

Итак, как, по-вашему, сделать HTTP и Router пакеты не связанными друг с другом?

Читать дальше…

Замаскированные зависимости

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

<?php
class Something
{
    private $collaborator;

    public function __construct( Collaborator $collaborator )
    {
        $this->collaborator = $collaborator;
    }
    
    // ...
}

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

Таким образом, мы можем переместить почти всё создание объекта в одно место: в фабрику. Существуют исключения, например, когда вы не хотите, или вам вовсе не нужно, чтобы фабрика создавала объект. Как правило, объекты-значения и доменные объекты создаются на месте.

Теперь у нас есть фабрика, которая может создавать все наши объекты. Для создания каждого объекта у неё будет по одному методу:

Читать дальше…

HTTP/2 Server Push с помощью Symfony HttpKernel

HTTP/2 поддерживает фичу под названием Server Push, позволяющую серверу отправлять таблицы стилей, JavaScript и другие статичные ресурсы в клиентский браузер без отдельных запросов.

Традиционно HTML страницы содержат ссылки на различные медиа-файлы, такие как JavaScript, CSS и изображения. Серверное приложение отправляет страницу браузеру, тот интерпретирует страницу и затем загружает с сервера статичные ресурсы.

Ваше серверное приложение, скорее всего, знает о том, какие ресурсы крайне важны для клиента. HTTP/2 Server Push даёт серверу возможность отправить определённые статические файлы прежде, чем клиент даже узнает, что они необходимы. Это приведёт к сокращению времени отрисовки при первой загрузке.

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

Это улучшенный способ встраивания статичных ресурсов, таких как изображения и CSS, в HTML страницу, поскольку отдельные ресурсы могут кэшироваться на клиенте. Те клиенты, которые не поддерживают Server Push, никак не отреагируют на дополнительные заголовки и продолжат функционировать так же, как и сегодня.

Читать дальше…

Почему следует избегать чрезмерной абстракции

Недавно, приступая к работе над существующим проектом, я прочитал документацию о нём. «Абстрагируйте, когда это возможно» было написано в начале contributing.md. Стало сразу ясно, что проект содержит больше абстрактных классов, чем любой другой нормальный проект. Такой подход приводит к слишком связанному и часто неизменному коду.

Почему же «абстрагируйте, когда это возможно» — вовсе не хороший совет, расскажу далее.

Читать дальше…

Автоинкрементные идентификаторы: раздача своих данных

Учебные руководства и значения по умолчанию в ORM системах нам всегда говорят, что каждая таблица SQL должна иметь автоинкрементный ID. Это странная общая ошибка старых и новых «туториалов» в различных формах. Почему автоинкрементные идентификаторы представляют проблему? Потому, что это означает, что люди могут скачать вашу базу данных.

Читать дальше…

Шагаем вперед с MVC: CQRS

Забываете ли вы иногда, что моделирует ваша модель? Не выходят ли из под контроля ваши контроллеры? Современные MVC фреймворки, такие как Ruby on Rails и Laravel, дают возможность чрезвычайно легко получить полноценные веб-приложения, готовые к продакшену с невероятно высокой скоростью. С помощью находчивых контроллеров в CRUD стиле небольшая команда, иногда состоящая из одного человека, может запустить RESTful веб-приложение в комплекте с пользователями, сообщениями в блоге, комментариями и административными возможностями в течении нескольких часов. Когда это облегчает массу объёма работы, это прекрасно. Но все мы знаем, что проекты могут быстро превратиться в базу кода, которая станет ночными кошмарами по развёртыванию и поддержке без прочной поддержки. Распределение ответственности на команды и запросы (CQRS) является одним из паттернов, которые мы использовали в Grok, когда наши приложения, основанные на MVC, стали развиваться в более сложные части программного обеспечения.

Читать дальше…

Symfony Routing — Как сопоставить маршрут на основе хоста

Вы можете указать соответствие входящего запроса на основе HTTP хоста.

mobile_homepage:
    path:     /
    host:     m.example.com
    defaults: { _controller: AcmeDemoBundle:Main:mobileHomepage }

homepage:
    path:     /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }

Оба маршрута соответствуют одному и тому же пути — /, однако первый будет соответствовать запросу, только если хостом будет являться m.example.com.

Читать дальше…