Beer::PHP 🍺
رفتن به کانال در Telegram
Здесь публикуются короткие заметки о PHP, Linux, Unit Testing, DB, OOP, etc., выдержки из статей, книг, видео, курсов и других материалов. Теперь тебе больше не нужно перерывать тонны информации ;) @genkovich — написать автору канала.
نمایش بیشترکشور مشخص نشده استدسته بندی مشخص نشده است
3 068
مشترکین
اطلاعاتی وجود ندارد24 ساعت
اطلاعاتی وجود ندارد7 روز
اطلاعاتی وجود ندارد30 روز
آرشیو پست ها
3 068
🔴 Релиз PHP 8.1, запуск PHP Foundation и истории переезда на 8.0
Для тех кто не в курсе, ребята подрубили крутой стрим в котором обсудят апдейты релиза и PHP Foundation, а также поделятся опытом и советами о том как переезжали на PHP 8.0.
Короче должно быть круто, подключайтесь!
https://www.youtube.com/watch?v=5D337gaVPa4
3 068
Настройка PHP-FPM (part 2)
Окей, вот мы переходим к самому интересному, по моему мнению, разделу: управление процессами.
👉 С помощью параметра
pm можно настроить стратегию запуска дочерних процессов. Всего есть 3 режима работы.
📌 Static — гарантирует, что обработка запросов всегда доступна фиксированному количеству дочерних процессов (кол-во которых устанавливается с помощью pm.max_children). При такой схеме кол-во дочерних процессов не меняется, а значит они всегда занимают определенный объем ОЗУ и в случае пиковых нагрузок у вас могут быть сложности (клиенты будут становиться в очередь). С другой стороны — запросам не нужно ждать запуска новых процессов, а значит на это не тратятся дополнительные ресурсы, что делает static самым быстрым подходом. Такую стратегию лучше использовать когда у вас постоянная высокая нагрузка и большой объём оперативной памяти.
pm.max_children — очень важный параметр, который работает для всех трёх режимов, означает максимально возможное количество дочерних процессов, если значение будет слишком маленьким, то при возрастании нагрузки, лимит исчерпается и ваш сайт начнёт тупить, если слишком большим - исчерпается оперативная память и что-то упадёт;
❓ Как посчитать значение pm.max_children?
Один из способов — от оперативной памяти. Безопаснее всего когда ваш fpm работает изолировано, например в контейнере, и ему выделен определенный ресурс. В противном случае высока вероятность что-то не учесть, а конкурирующие процессы будут недовольны таким положением дел.
Для этого определяем сколько памяти кушает каждый наш процесс (найдите для вашей ОС, вот пример для Ubuntu):
ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'
Например я получил, что в среднем один процесс кушает 60 МБайт. Допустим у меня на серваке всего 16 ГБайт, 8 из них уже использует БД (кеши и прочее), еще 2 другие приложения, остаётся 6. Какой-то запас необходимо оставить, итого 4 ГБ / 60 МБ = 66 процессов.
⚡️ От себя рекомендую получившееся число изначально разделить еще на 2 и двигаться дальше от этой отправной точки эмпирическим путём, внимательно наблюдая за метриками сервера.
📌 Dynamic — регулирует количество дочерних процессов в зависимости от нагрузки исходя из значений конфигурационного файла. Данный пул больше всего подходит когда нужна экономия ресурсов (за счет уменьшения дочерних процессов при простое), но при этом бывают пиковые всплески, которые необходимо обработать.
Помимо pm.max_children в настройке этой стратегии принимают участие еще 3 параметра:
✅ pm.start_servers — количество процессов, запускаемых при старте PHP-FPM. Видел 2 рекомендации по подсчёту: Значение равно кол-ву ядер (но не нашел информации где это обоснованно) или 25% от pm.max_children, который считается также, как для static.
✅ pm.min_spare_servers — минимальное количество бездействующих дочерних процессов. Чтобы новый процесс не создавался прямо в момент подключения нового клиента — PHP-FPM создаёт процессы заранее. Например на старте у нас было 10 процессов, и значение min_spare_servers мы установили равным 10. Пришел клиент и сразу подключился к одному из поднятых процессов, а в это время заботливый FPM создаёт еще один 11й процесс, чтобы бездействующих снова стало 10. Когда общее кол-во процессов упирается в pm.max_children, то новые свободные процессы не создаются (что логично). Также рекомендуют брать значение 25% от pm.max_children.
✅ pm.max_spare_servers — максимальное количество бездействующих дочерних процессов. При падении нагрузки, PHP-FPM будет убивать лишние процессы высвобождая ресурсы. Если значение свободных процессов больше, чем pm.max_spare_servers, то главному процессу будет отправлен SIGCHLD, чтобы он сократил кол-во дочерних процессов и они всегда находились в пределе между pm.min_spare_servers и pm.max_spare_servers. Считают как 75% от pm.max_children.
👍 Как вы уже догадались, вас ждёт 3я часть из данного цикла. Если вам есть что добавить — обязательно пишите мне лично или добавляйтесь в наш уютный чатик :)
#php #server #middle #source3 068
Настройка PHP-FPM (part 1)
Ну что, вы просто не оставили мне выбора, почти 400 🍺, круто! Сразу оговорюсь, что материал, который здесь приведен — очень сухая и субъективная выжимка, потому как материала слишком много (и уже получилось несколько частей), но я не стал углубляться в дебри. Постарался сделать так, чтобы было понятно откуда ноги растут и куда копать, если что.
👉 Давайте по порядку. В конфигурации нас будут интересовать 2 места:
• основной файл конфигурации
/etc/php/(версия)/fpm/php-fpm.conf
• и файлы пулов /etc/php/(версия)/fpm/pool.d/
📌 С понятием Pool вы будете сталкиваться достаточно часто. Pool – это группа процессов, выделенная для обработки запросов, поступающих на определённый порт или unix-socket. В PHP-FPM возможно настраивать (и использовать) сразу несколько пулов, для решения разных, отдельных задач.
⚡️Разделение приложений по пулам позволяет предотвратить ситуацию, когда один высоконагруженный сервис постоянно держит занятыми процессы-обработчики, не давая нормально работать другим, более лёгким приложениям
Для того чтобы создать несколько отдельных пулов, внутри директории pool.d следует создать отдельный файл под каждый пул. Сразу скажу, что настройки в этих файлах будут иметь приоритет выше, чем те, что в php.ini. По умолчанию у нас описан пул в файле www.conf. Открыв его мы сразу видим [www], это и есть наше имя пула. В зависимости от потребностей вы можете создать пул с любым именем. Например вы можете настроить отдельными пулами [backend] и [frontend]. Имя пула должно быть в самом верху в квадратных скобках.
✅ На что следует обратить внимание, это то как проходят данные от веб-сервера к вашим php процессам. Это отражено в директиве listen:
listen = /var/run/php8-fpm.sock
По факту, таким образом в нашей операционной системе мы задаём адрес (socket или host:port) , который будет принимать FastCGI-запросы. И затем уже в нашем nginx конфиге мы указываем по какому адресу нам стоит обращаться, а следовательно какой пулл с какими настройками будет использован:
### nginx config ###
location ~ \.php$ {
...
fastcgi_pass unix:/var/run/php8-fpm.sock;
...
}
🔨 Коротко про права доступа: Чтобы кто попало не писал в наш сокет - запрещаем это делать путём указания прав доступа к нему. Для этого предназначены строчки listen.owner, listen.group и listen.mode. По умолчанию стоит группа и пользователь www-data (как у вашего веб-сервера) и права 0660, что означает, что владелец и пользователь могут читать и редактировать, а все остальные не могут делать ничего.
❓ Помните в прошлом посте был пример про "очередь", в которой будет ожидать наш запрос, если он еще не обрабатывается каким-то процессом?
Так вот, параметр listen.backlog отвечает за размер очереди одновременно ожидающих подключений к нашему сокету. В зависимости от версии и операционной системы вы можете увидеть значение по умолчанию 511, 128, 65535, -1 (подразумевая неограниченно, но это не так) и т.д.
Какое значение установить? Зависит от задачи которую вы решаете:
❗️Если значение слишком большое, а php-fpm не успевает обрабатывать все запросы, то nginx дождется тайм-аута и отключится, выкинув 504 ошибку.
❗️Если это значение установлено слишком маленьким, то с одной стороны клиентские запросы, вообще не могут попасть в очередь и выдается сообщение об ошибке 502, однако ваш сервер не тратит лишние ресурсы на хранение запросов в очереди.
👌 Лучший метод расчета — определить размер в соответствии с QPS (query per second) у вашего production сервера, накинуть 30-50%, и убедиться, что железо справляется с таким кол-вом запросов. Тогда во время пиковой нагрузки (черная пятница/новый год) вы конечно рискуете, что некоторые из пользователей отвалятся получая 502, но не потеряете всех из-за зависшего железа.
🧐 Думаю на сегодня достаточно, в следующей части рассмотрим настройки самого Process Manager (pm), узнаем, какие стратегии лучше использовать для решения различных задач. Если у вас есть вопросы — их можно обсудить со мной и другими подписчиками в нашем чатике.
#php #server #middle #source3 068
PHP Jobs
Тем временем спешу поделиться с вами прикольным каналом, который только появился на просторах ТГ. Если вдруг вы находитесь в поиске подходящей работы, на любую позицию от Junior до CTO, то вам следует обратить внимание на канал PHP JOBS.
👉 Подписывайтесь и получайте информацию о свежих и актуальных вакансиях по вашему профилю :)
3 068
Fluent interface. Evil or not?
Ну а пока я готовлю материал по теме настройки fpm (оказалось не очень просто вместить его в небольшой и понятный пост), решил поднять довольно старую тему, о которой не так уж много сказано.
Прежде всего давайте синхронизируемся что же такое fluent interface?
Каждый из вас наверняка видел конструкцию наподобие:
$example = Example::create()->addFoo()->deleteBar()->build();
👉 А добиться этого можно с помощью вот такого нехитрого фокуса [pic | code ]. При такой реализации мы сможем добавлять в массив строки не вызывая каждый раз переменную [pic | code ].
На первый взгляд выглядит отлично, достаточно удобно и позволяет писать меньше кода. Однако, не всё так радужно, как кажется на первый взгляд.
📌 Первая проблема — подобные конструкции начинают вставлять везде, где только можно. Возьмём пример с какой-нибудь сущностью Order. Предположим у вас есть сеттеры (об этом зле у нас будет отдельный разговор, но потом. Пока предположим, что у вас они есть) setId(), setTitle(), setDescription(). Всё выглядит достаточно удобно, в сущности всего 3 метода, мы можем вызывать их цепочкой. Однако, представим, что нам нужно добавить информацию о доставке setCountry(), setCity(), setAddress().
❌ Что мы делаем? Правильно, мы берем и просто добавляем еще 3 метода, потому что нам хочется вызывать их цепочкой. Затем мы хотим добавить инфу о получателе и добавляем еще 5 методов, инфу о скидках — еще 4 и т.д. В итоге наша сущность раздувается до нереальных размеров, данные никак не разбиты на логические (бизнесовые) куски (смотри whole objects).
К нам приходит менеджер и говорит — "Нельзя, чтобы описание товара было заполнено без тайтла, а адрес не должен быть указан без страны и города". И тут начинается веселье, в котором в сеттеры добавляются проверки, а у нашего fluent interface появляется необходимость вызывать методы в определенной очереди, которая совсем не очевидна другому разработчику. Чем больше правил — тем больше хаоса, рано или поздно кто-то таки выстрелит себе в ногу.
📌 Второе — декорирование. Давайте представим, что мы хотим расширить наш класс Example и добавить логирование [pic | code ]. На первый взгляд всё выглядит логично, но сколько раз вызовется логгер? Один(!). А всё потому, что нашу обёртку теперь тоже нужно сделать "текучей", что тоже не сразу очевидно и часто бывает местом для багов.
📌 Третье — их сложнее мокать. Не секрет, что мокая объект мы создаем Null Object, где все методы являются заглушками. Чтобы протестировать логику и случайно не оборвать нашу цепочку — нам придётся описывать КАЖДЫЙ метод (а напомню, что в примере с Order их больше 20) примерно такой конструкцией, даже если на самом деле его вызов ни на что не влияет в нашем тесте.
$example
->expects($this->any())
->method('addBar')
->willReturnSelf();
📌 Если копнуть еще глубже, то можно найти проблемы с обратной совместимостью, нарушением инкапсуляции, сложностью с отслеживанием изменений, однако не всё так плохо.
👍 Есть места, где использование данного похода достаточно хорошо себя показывает и это билдеры (в множестве их проявлений):
$queryBuilder
->select('u')
->from('User u')
->where('u.id = :identifier')
->orderBy('u.name', 'ASC')
->setParameter('identifier', 100);
❓ Так зло или нет?!
Сам по себе данный подход ни в коем случае не является абсолютным злом, однако, прежде чем его использовать вам следует хорошо подумать:
1. Не создаёте ли вы себе дополнительных проблем?
2. В какой момент и что пошло не так, если в Entity вам нужно засэтить десяток полей?
3. Точно ли всё очевидно?
Хорошо и правильно, если данный подход вы используете с умом, там где это уместно. Тогда fluent interface действительно сделает ваш код лаконичнее, а не породит несколько мест для новых багов.
#php #junior #source3 068
CGI, FastCGI, php-fpm
Уверен, многие из вас видели эти аббревиатуры, но, как оказалось, не все знают, как они связаны и что обозначают. Конечно, эта тема может быть более актуальна тем, кто занимается настройкой ПО (типа DevOps), но считаю, что хотя-бы общее представление должно быть у всех, кто так или иначе занимается разработкой на PHP, потому решил поверхностно описать эти вопросы.
👉 CGI
Common Gateway Interface — это стандарт (протокол, спецификация, соглашение, набор правил), который описывает, как веб-сервер должен запускать скрипты (в т.ч. PHP, а также другие программы), как должен передавать им параметры HTTP-запроса и как скрипты должны передавать результаты своей работы веб-серверу. То есть CGI был разработан для того, чтобы расширить возможности веб-сервера и дать возможность создания и обработки динамического контента.
👉 FastCGI
По факту это дальнейшее развитие технологии CGI, является более производительным и безопасным. В чем же главное отличие?
В CGI-режиме на каждый запрос создается отдельный процесс, "умирающий" после окончания обработки. В FastCGI процесс работает в качестве демона, то есть один и тот же процесс обрабатывает различные HTTP запросы один за другим. PHP из коробки умеет работать и в FastCGI режиме.
👉 PHP-FPM
FastCGI Process Manager — альтернативная реализация PHP FastCGI, которая позволяет вам достаточно гибко настраивать те самые процессы, о которых я писал выше.
❓ Как это работает?
📌 Представим, что в наше приложение одновременно приходит 50 клиентов. Сначала они обращаются в наш NGINX, который по факту пробрасывает запросы сквозь себя на PHP-FPM (за исключением запросов за статическими ресурсами/файлами), а дальше PHP-FPM пытается обработать все запросы с помощью своих процессов (воркеров).
📌 Допустим у нас запущено 5 воркеров, как на картинке. В таком случае во время одновременного запроса первые 5 клиентов будут обрабатываться сразу, а остальные 45 становятся в очередь и ждут, когда первые 5 закончат обработку. PHP-FPM позволяет задавать настройки в зависимости от ваших потребностей, будь то динамическое увеличение воркеров для того чтобы клиенты не ждали в очереди или экономия ресурсов с целью ускорения обработки запросов со статическим кол-вом воркеров.
👍 Если интересно более подробно почитать про настройку php-fpm, то ставь 🍺. Надеюсь стало немного понятнее и теперь никто не будет впадать в ступор при виде этих аббревиатур. 😉
#php #server #source
3 068
DRY (Don't Repeat Yourself)
Буквально сегодня сидел и смотрел на пачку похожих классов, код которых на 98,2% одинаков. Очень сильно подмывало схлопнуть это всё, но как правильно это сделать? Давайте разберемся подробнее.
👉 Многие считают, что DRY запрещает дублировать код, но это не так. Вся суть таится немного глубже. Давайте разберемся с определением:
"Каждая часть знания должна иметь единственное, непротиворечивое и авторитетное представление в рамках системы"
❓ Вся тайна кроется как раз в определении "часть знания". Что же это такое?
👍 Речь идёт не о написанном коде, а о знаниях в "предметной области" или "бизнес правилах". Давайте рассмотрим пример { pic | gist }
В данном случае код выглядит одинаково, однако, это может продиктовано абсолютно разными требованиями бизнеса:
📌Мы ограничиваем корзину тремя единицами товара из-за высокого спроса, а нам выгодно продать его как можно большему кол-ву покупателей.
📌В то же время мы ограничиваем доставку тремя единицами, потому что наш транспорт физически не может вместить большего объема.
Подсознательно нам хочется взять и вынести дублирующийся код в один источник, но что если какое-то из правил изменится? Например мы купили новый транспорт для доставки и теперь можем доставлять до 10 единиц товара?
❗️ Очень важно, чтобы у вашего кода могла быть только "одна причина для изменения" (прямо как в SRP), ведь правила вашего бизнеса в одной предметной области могут (и должны) меняться независимо от другой.
💡 Когда-то М. Фаулер популяризировал так называемое Rule of three. Звучит примерно так: "Два экземпляра аналогичного кода не требуют рефакторинга, но, когда аналогичный код используется три раза, его следует извлечь в новую процедуру." Это правило, в первую очередь, отлично помогает избежать преждевременного обобщения, когда с виду похожие вещи имеют разные зоны ответственности и потому не являются дублированием.
👌 DRY — это принцип, однако принципы — не правила. Они лишь инструменты, помогающие идти в правильном направлении. Очевидно, что не стоит везде повторять бизнес-логику, но также не нужно и объединять всё подряд. Необходимо искать баланс, который зависит от текущей ситуации.
#php #junior #source
3 068
Приглашаем тебя на бесплатную программу обучения JS+PHP Full Stack! 🚀
Ты — студент или начинающий программист?
Интересуешься разработкой на РНР и VueJS?
Записывайся на бесплатную программу обучения от NIX!
За три месяца вместе с опытными экспертами NIX ты на практике освоишь основные инструменты JS+PHP-разработчика. Полученные знания и навыки помогут тебе пройти собеседование на позицию Junior РНР Developer в нашу команду.
Что мы ожидаем от тебя:
🔹 ты понимаешь, как устроен интернет и как происходит обмен информацией в сети;
🔹 знаешь основные принципы ООП;
🔹 разбираешься в работе любой СУБД, в исключениях и интерфейсах;
🔹 владеешь базовыми знаниями SQL и принципами нормализации БД;
🔹 понимаешь, как работает PHP интерпретатор, как строить циклы и условия;
🔹 знаком с разметкой HTML (основные теги, структура страницы);
🔹 понимаешь работу любой системы контроля версий.
3 месяца, 30 занятий в группе с ментором, трижды в неделю с возможностью подключаться в Zoom.
Узнай больше о программе обучения JS+PHP Full Stack — переходи по ссылке в описании нашего профиля!
3 068
Decorator pattern
Не подумайте, меня не покусал Егор Бугаенко (для тех кто в теме, кто нет — погуглите), мои взгляды не настолько радикальны, однако я действительно считаю, что этому паттерну уделяют мало внимания. Потому решил познакомить с ним тех, кто не знаком и освежить в памяти для тех, кто уже давно им пользуется.
Декоратор — (wiki) структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту.
👉 Если простым языком, то суть данного паттерна заключается в "оборачивании" существующего объекта новым функционалом, при этом оригинальный интерфейс объекта остается неизменным. В данном примере
WrapperObject и есть наш декоратор.
❓ В чем преимущества?
1. Его не получится просто так создать без существования базового класса.
2. Так как базовый класс и класс обертка имплементируют один интерфейс — то они взаимозаменяемы.
3. Мы расширяем поведение без изменения исходного кода.
Стоп, да это же прям Open-Closed Principle! И да, это отличная альтернатива наследованию. Также вы можете использовать несколько разных обёрток одновременно.
❗️ Да, клиентский код выглядит не круто, да и искать все места где вызывается базовый класс, чтобы прицепить обёртку бывает проблематично (особенно в долгоживущих проектах). Однако в фреймворках этот вопрос легко решается. Например в Symfony достаточно добавить всего несколько строк:
Представим, что у нас есть какой-то Mailer, который мы описали в services.yaml и теперь мы хотим логировать отправку всей почты. Для этого у контейнера есть директива decorates. Подобная запись подменит основной mailer на mailer_logger и наши письма начнут начнут логироваться. Для ссылки на исходный класс нужно использовать decorating_service_id + .inner (или просто '@.inner' начиная с Symfony 5.1).
👍 Но что если мы хотим не только логировать, но и отправлять наши письма через очередь? Нет проблем, мы можем добавить еще одну запись. Но как задать порядок в котором будут вызваны декораторы? Для этого существует директива decoration_priority (по умолчанию 0). Соответственно чем выше приоритет — тем раньше применится декоратор (всё логично). Например такой код сначала залогирует (1), а потом уже отправит в очередь (2) наше сообщение:
$this->services['mailer'] = new LoggerDecorator(new QueueDecorator(new Mailler()));
#php #oop #patterns #middle3 068
Code review sessions
Еще раз привет, для всех, кто пропустил предыдущую новость 😉
Один из наших подписчиков на чистом энтузиазме и морально волевых продвигает идею взаимного ревью для ребят, которые занимаются фрилансом или в целом не имеют команды.
👍 Уже прошло несколько полноценных ревью сессий, в которых приняли участие десятки разработчиков.
👉 Так что залетай и подписывайся eсли тебе не хватает ревью или же сам хочешь поделиться своими знаниями с другими :) Также поделись своим мнением или советом, чтобы ребята смогли сделать продукт еще круче!
3 068
Спешите присоединиться к бесплатному онлайн-интенсиву по основам программирования на языке PHP, который пройдёт 27–29 сентября в 19:00 по московскому времени. Познакомитесь с одним из самых востребованных языков в веб-разработке и напишете своё первое приложение — игру «Поле чудес».
Интенсив подойдёт и новичкам, и начинающим разработчикам.
Подробная программа: ▶️ https://clc.to/URXSJg
☝️Чтобы интенсив прошёл максимально эффективно, установите PHP 8 и среду разработки PhpStorm. После регистрации мы пришлём вам ссылку для скачивания.
💬 Спикер интенсива — веб-разработчик с девятилетним опытом Михаил Волков. Он руководит направлением «Обучение» в QSOFT, создал образовательный проект BitrixCasts, ведёт блог о программировании на PHP и JavaScript.
⭐️ Все участники получат электронную книгу Кей Петерсон и Дэвида Колба «Век живи — век учись» издательства МИФ. А те, кто сдаст домашнее задание, — сертификаты на 5 000 рублей на любой курс Skillbox.
🔥А еще дарим вам чек-лист «Как создать игру «Поле-чудес» на PHP», он поможет по шагам воссоздать сайт, который вы сделаете на интенсиве!
Подключайтесь к прямым эфирам!
3 068
Локальная разработка пакетов (composer + phpstorm)
Буквально пару дней назад мой коллега спросил "а как ты работаешь с мультирепозиториями?", "О чём ты?" — спросил я, "Ну вот тебе нужно сделать sdk и сразу протестить внутри приложения, что ты делаешь?". И вот уже через несколько часов я действительно разбирался с этой проблемой, решением которой захотел поделиться.
👉 Представим, что у вас есть проект и вы решили сделать отдельный пакет, который будет решать какую-то задачу внутри проекта. Например собственное SDK для внешнего API, которое хотите внедрить и тестить прямо в своём проекте. С чего начать?
0. создаете папку
1. в ней composer init
2. создать структуру папок и прописать psr-4 (вот пост с подробностями)
3. не забудьте
git init :) точно пригодится
❓Дальше начинается самое интересное. Как же подключить наш локальный пакет к существующему vendor?
Оказывается всё достаточно просто. Нужно добавить в composer.json директорию repositories, добавить запись с типом path, а урл — относительный путь в директорию с пакетом:
"repositories": [
{
"type": "path",
"url": "../my-package"
}
],
"minimum-stability": "dev"
и не забыть понизить minimum-stability до dev. Выглядит вот так.
👍 Дальше делаем composer require package/name и вуаля! Теперь мы можем смело править файлы пакета, без дополнительных коммитов, пуша в удаленный репозиторий и прочих прелестей. Всё потому, что фактически композер сделал симлинку и подтягивает изменённые файлы напрямую.
💁♂️ Ну, а для того чтобы во время разработки не прыгать между окнами, достаточно добавить в PHPStorm -> Settings -> Version Control тот самый локальный репозиторий, затем открыть папку проекта и выбрать attach. После этого находясь в одном окне вы можете спокойно править файлы и проекта и пакета, при этом каждый будет, пуллиться, фетчится и даже коммититься в свой гит репозиторий :)
#middle #phpstorm #packages3 068
⚡️ ЭТОТ ЯЗЫК ПРОГРАММИРОВАНИЯ МОЖНО ОСВОИТЬ ЗА 1 МЕСЯЦ
Только для PHP необходим минимальный набор знаний. Это язык программирования с САМЫМ низким порогом входа.
А на нём работают YouTube, Facebook, Wikipedia...
Laravel – это идеальная экосистема для тех, кто хочет устроиться на работу максимально быстро. Этому учат на канале @web_craft
Опытные разработчики создали этот канал, чтобы люди учились работе с Laravel и за пару месяцев находили работу в IT-гигантах.
Открывай, изучай — t.me/web_craft
3 068
Проложи свой маршрут по Go вместе с экспертами Ozon!
Route 256
Highway to ecom
💎Бесплатно
💎Оффер лучшим выпускникам
💎Без собеседования на входе
💎Два месяца
💎Старт 25 сентября
Ты сможешь работать с асинхронным кодом, использовать Prometheus и Grafana для мониторинга и многое другое.
Будет предварительный отбор. Подай заявку до 25 сентября включительно и перезапусти карьеру в IT: https://ozon.ru/t/U3c8j
3 068
Битовые операции (часть 2)
В прошлой части мы рассмотрели побитовые сдвиги влево и вправо, сегодня рассмотрим остальные 4 операции — AND & , OR | , XOR ^, NOT ~.
Для примера рассмотрим простую систему разграничения прав доступа к сайту.
📌 У нас будут доступны следующие права доступа: Чтение, Создание, Редактирование, Удаление. То есть всего 4 значения, их можно представить в виде 4-х битного числа, в котором 1 — означает, что у пользователя есть данное право, а 0 — нет. Разберем код из предыдущей части:
define('U_READ', 1 << 0); // 0001
define('U_CREATE', 1 << 1); // 0010
define('U_EDIT', 1 << 2); // 0100
define('U_DELETE', 1 << 3); // 1000
define('U_ALL', U_READ | U_CREATE | U_EDIT | U_DELETE); // 1111
В первых 4 строках мы задали константы с помощью сдвига влево. А в пятой строке использовали оператор OR |. Он выполняет операцию над каждым битом своих операндов. Бит результата устанавливается, если соответствующий бит установлен хотя бы в одном операнде. Например:
$x = 3; // 0011
$y = 5; // 0101
echo $x | $y; // 0111 (7)
Таким образом мы можем задать любые разрешения для пользователя:
$userPermission = U_READ; // только право чтения
$userPermission = U_READ | U_CREATE; // можно читать и создавать
$userPermission = U_ALL ^ U_DELETE; // все права кроме удаления
$userPermission = U_ALL & ~ U_DELETE; // тоже все права кроме удаления
📌 В данном примере мы видим XOR ^ (исключающее или). Бит устанавливается, если соответствующий бит установлен в одном (но не в обоих) из двух операндов.
$x = 3; // 0011
$y = 5; // 0101
echo $x ^ $y; // 0110 (6)
В нашем случае:
U_ALL 1111
U_DELETE 1000
RESULT 0111
📌 В следующей строке сразу 2 оператора AND & и NOT ~. Оператор & выполняет операцию логическое И над каждым битом своих операндов. Бит результата устанавливается, если соответствующий бит установлен в обоих операндах:
$x = 3; // 0011
$y = 5; // 0101
echo $x & $y; // 0001 (1)
📌 Оператор NOT ~ представляет собой унарный оператор, указываемый перед своим единственным операндом. Он выполняет инверсию всех битов операнда. Из-за способа представления целых со знаком в PHP применение оператора ~ к значению эквивалентно изменению его знака и вычитанию 1.
$y = 5; // 0101
echo ~$y; // 1010 (-6)
Таким образом в нашем примере сначала сработает оператор NOT. U_DELETE из 1000 станет 0111, а затем вызовется оператор &
U_ALL 1111
~ U_DELETE 0111
RESULT 0111
❗️ Разница между этими вариантами в том, что в первом случае просто переключается бит, если был 1, то станет 0, и наоборот. Второй же вариант делает бит равным 0, независимо от его текущего значения.
Если мы хотим убрать какое-нибудь право доступа, то пишем так:
$userPermission &= ~ U_DELETE; // запретить удаление
👉 Для проверки битов (в нашем случае прав доступа) можно использовать следующие конструкции.
if ($userPermission & U_READ) // есть ли право чтения?
if ($userPermission & (U_READ | U_DELETE)) // есть ли право чтения и/или удаления
Еще один пример:
// Вместо
if ($error['type'] == E_ERROR || $error['type'] == E_PARSE || $error['type'] == E_COMPILE_ERROR) {}
// Или
if (in_array($error['type'], [E_ERROR, E_PARSE, E_COMPILE_ERROR])) {}
// Можно использовать
if ($error['type'] & (E_ERROR | E_PARSE | E_COMPILE_ERROR)) {}
👍 Несмотря на то, что коды ошибок в PHP специально заточены под битовые операции, тем не менее, достаточно часто для проверки кодов ошибок используются обычные операторы сравнения. Но теперь вы знаете, что можно сравнивать и побитово ;)
#php #junior #source
3 068
Пройдите онлайн-курс от Skillbox и станьте востребованным PHP-разработчиком!
PHP входит в десятку самых популярных языков программирования по индексу TIOBE. На этом серверном языке написано большинство CMS, в том числе и WordPress, на котором работает 65% всех сайтов в мире. Чтобы поддерживать работу старых проектов и писать веб-приложения с нуля, компании нанимают PHP-разработчиков.
Вы с нуля научитесь программировать сайты и веб-приложения на PHP, освоите фреймворк Laravel, напишете облачное хранилище и поработаете над интернет-магазином в команде. Сможете устроиться на позицию Junior-разработчика.
Прямо сейчас более 2 800 компаний ищут PHP-разработчиков, а средняя зарплата, по данным HeadHunter, составляет 90 000 рублей!
Расходы за первые 3 месяца обучения берёт на себя Skillbox.
В конце обучения опытные HR-специалисты подберут лучшие вакансии, подготовят к собеседованию и помогут получить работу.
Переходите по ссылке: https://clc.to/znpEQg и узнайте больше о программе обучения.
3 068
Хочешь принять участие в CodeReview?
👍 Один из подписчиков Beer::PHP недавно рассказал мне о своей идее проведения взаимного ревью для ребят, которые занимаются фрилансом или в целом не имеют команды.
Короче, как по мне очень прикольная идея создания подобного комьюнити. В дальнейшем ребята хотят запилить платформу, которая позволяла бы получать ревью от опытных разработчиков, а также давать свой фидбэк тем, кто в этом нуждается.
📌На данный момент ребята создали телеграм канал, в котором уже есть активности, а также апдейты по прогрессу этой идеи.
👉 Так что залетай и подписывайся eсли тебе не хватает ревью или же сам хочешь поделиться своими знаниями с другими :)
3 068
Битовые операции (часть 1, сдвиг влево и вправо)
📌 В мире PHP эти операции встречаются редко, однако в статьях, книгах, либках и других источниках легко можно встретить запись типа:
~
$memory = memory_get_usage() >> 20;
И тут наступает ступор, что за ">>"? Лезешь в доку а там
$a >> $b — Сдвиг вправо. Все биты переменной $a сдвигаются на $b позиций вправо (каждая позиция подразумевает "деление на 2").
❓ Чё сдвигается, куда? Зачем вообще оно надо? Давайте разбираться.
Думаю многие знают, что число в двоичной (бинарной) системе исчисления представляет собой набор нулей и единиц. Например число 6 будет представлено как 00000110.
👍 Побитовый сдвиг в PHP - это арифметическая операция. Биты, сдвинутые за границы числа, отбрасываются. Сдвиг влево дополняет число нулями справа, сдвигая в то же время знаковый бит числа влево, что означает что знак операнда не сохраняется. Сдвиг вправо сохраняет копию сдвинутого знакового бита слева, что означает что знак операнда сохраняется.
Возвращаемся к нашему оператору >>
$n = 6; // 00000110
$k = $n >> 1; // 00000011
👉 Здесь четко видно, что мы отбросили самый правый бит, а слева дополнили нулём. Соответственно запись 00000011 в двоичном представлении равна 3 в десятичном. То есть фактически сдвинув один бит — мы поделили на 2, а если сдвинем на 2 бита, то еще раз поделим на 2 (то есть на 4), на 3 бита — получится что на 8.
❗️ Стоп. Да это же степени двойки!
Возвращаясь к нашему первому примеру >> 20, получится, что мы делим наше исходное значение на 2 в степени 20. Легко запомнить, что 2^10 = 1024. Тогда:
$memory = memory_get_usage() / (1024 * 1024);
Так как функция memory_get_usage() возвращает значение в байтах, то мы всего-лишь перевели всё в Мб. Получается достаточно удобно:
>> 10 приводит в Кб
>> 20 приводит в Мб
>> 30 приводит в Гб
В то время как сдвиг вправо означает деление, то сдвиг влево — умножение.
$y = 5; // 000000101
echo $y << 2; // 000010100 (5 * 4 = 20)
❤️ Однако, самое вкусное использование побитовых операций заключается не в умножении и делении, а именно в использовании побитовой маски, например для разграничений прав доступа, или других подобных операций:
define('U_READ', 1 << 0); // 0001
define('U_CREATE', 1 << 1); // 0010
define('U_EDIT', 1 << 2); // 0100
define('U_DELETE', 1 << 3); // 1000
define('U_ALL', U_READ | U_CREATE | U_EDIT | U_DELETE); // 1111
Выглядит интересно, но об этом и других битовых операциях мы поговорим в следующей части :)
#php #junior #source3 068
Атрибуты (part 1, что это такое?)
Сейчас много разговоров о PHP 8, ещё больше о 8.1. Есть куча крутых фишек, есть спорные, а есть те, с которыми лень разбираться. Одна из таких атрибуты. К сожалению только несколько человек из тех, кого я собеседовал, смогли ответить на вопрос — что это такое. Причины могут быть разные (еще не перешли на 8 / долго и лениво читать / оно как-то работает и пусть), но для тех, кто всё же хочет чуть-чуть разобраться я пишу этот пост.
👉 Сама концепция уже давно известна, мы много лет используем аннотации (докблоки) для добавления каких-то метаданных к классам, свойствам, методам, переменным и т.д. Думаю всем давно известны примеры из PHPUnit, Doctrine ORM, Assert и многих других либок и фреймворков.
❓ Как это работало раньше?
В PHP докблоки «рефлексивны»: к ним можно получить доступ с помощью метода API Reflection getDocComment() на уровне функции, класса, метода и атрибута. Сначала нужно было получить комментарии класса и метода(ов), затем с помощью регулярных выражений распарсить необходимые аннотации. Код выглядел примерно так.
❓ Как это работает сейчас и в чём разница?
📌 Атрибуты дают фактически те-же возможности, однако этот способ конфигурации встроен непосредственно в язык, что даёт преимущество в скорости и читабельности. Если раньше некоторые не использовали аннотации, аргументируя это тем, что аннотации - по сути комментарии и не могут быть кодом для выполнения, а так же, функционал, который их использует, сложно распространять, то сейчас это часть языка. Вот так это может выглядеть теперь.
📌 Также можно (а согласно документации даже очень нужно) создавать классы атрибутов для этого нужно использовать атрибут
#[Attribute], который можно импортировать из глобального пространства имён с помощью оператора use. Они могут быть пустыми, но так-же могут содержать дополнительную информацию, в виде параметров которую также легко можно прочитать:
$attributes = $reflection->getAttributes(MyAttribute::class);
foreach ($attributes as $attribute) {
$attribute->getArguments();
}
Как вы поняли из примера, параметры будут переданы в конструктор класса MyAttribute. Параметры могут быть простыми скалярными типами, массивами, константами и т.д.
👌 В следующей части рассмотрим ограничения, повторяющиеся атрибуты, класс ReflectionAttribute и фильтрацию ;)
#php #middle #source3 068
👉 Сегодня я решил поделиться одним каналом, который читаю сам. Его ведет Артём Бородатюк, основатель Netpeak Gruop, где я работаю в одной из компаний :)
📌 Этот канал о бизнесе, о том как бизнес меняет мир вокруг нас, технологиях, IT, экономике и многом другом. Сильно помогает отвлечься от ежедневного рутинного кодинга и понять сколько прикольного происходит вокруг. Вот несколько прикольных постов, которые я отметил для себя:
1. Подробная инструкция "Как воплотить в жизнь идею IT-стартапа" с минимальными потерями времени и денег. Буквально недавно скидывал одному из подписчиков.
2. Тенденция выгорания - почему это происходит и как это остановить? Думаю это очень актуальная тема в нашей сфере.
3. Прикольный плагин для браузера, который составляет твой психопортрет и подбирает наилучшую стратегию для общения.
👍 Подписывайтесь, там еще много прикольных постов, которые стоит почитать ;)
