SensitiveParameter скрывает пароль во всех логах?
Параметр функции помечен атрибутом SensitiveParameter. Внутри функция записала его значение в прикладной лог, затем выбросила исключение. Что атрибут скроет?
Ответ:
Значение аргумента в stack trace, но не самостоятельную запись в прикладной лог. В трассировке оно представлено SensitiveParameterValue. В проверенном примере значение demo-secret осталось в файле лога. Атрибут появился в PHP 8.2, он не шифрует переменную и не очищает все места, куда код её передал. Если выводите аргументы исключения, отдельно проверяйте настройку zend.exception_ignore_args.
Назначение SensitiveParameter
Параметр функции помечен атрибутом SensitiveParameter. Внутри функция записала его значение в прикладной лог, затем выбросила исключение. Что атрибут скроет?
Ответ:
Назначение SensitiveParameter
Допустим, функция sum(int $value) объявлена в файле с declare(strict_types=1). Если вызвать sum('42') из другого файла без строгого режима, числовая строка может быть преобразована в int. Одного strict_types рядом с объявлением недостаточно, чтобы сделать все внешние вызовы строгими.
Если же strict_types включён в вызывающем файле, такая строка приведёт к TypeError. При этом int разрешено передавать в параметр float даже в строгом режиме.
Для возвращаемого значения правило другое: режим определяется файлом, где объявлена функция.
Строгая типизация не заменяет проверку входных данных и не меняет правила операторов сравнения. Здесь речь именно о проверке объявленных скалярных типов.
Please open Telegram to view this post
VIEW IN TELEGRAM
www.php.net
PHP: Type declarations - Manual
👍2
До 31 октября в Proglib Academy можно выбрать два курса и заплатить только за один.
Например, можно совместить:
💥 ИИ для разработчиков — применение нейросетей в повседневной разработке: работа с кодом, тестирование и ревью.💥 Разработка ИИ-агентов — архитектура агентов и создание собственных AI-решений.
Вместе курсы стоят 108 000 ₽, но по акции оба обойдутся в 59 000 ₽. Экономия — 49 000 ₽
Интересуют Python и ИИ или алгоритмы и архитектура? Можно выбрать любые два курса из каталога.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱1👾1
Одна из причин ограничения — возможность вызова зависит от контекста доступа. Например, массив с объектом и именем его private-метода может быть вызываемым внутри класса, но недоступным для вызова снаружи.
Поэтому недостаточно однажды проверить значение при записи в свойство и считать, что оно будет вызываемым в любом месте программы.
Для хранения обработчика можно использовать свойство типа Closure. Переданный callable при необходимости преобразуют через Closure::fromCallable(). Полученное замыкание сохраняет возможность вызова с учётом контекста, в котором оно было создано.
С PHP 8.1 доступен и синтаксис создания вызываемого объекта первого класса, например $object->method(...). Правила видимости при его создании всё равно действуют.
Please open Telegram to view this post
VIEW IN TELEGRAM
www.php.net
PHP: Properties - Manual
В PHP 7 и новее Exception и Error образуют две отдельные ветки, которые реализуют общий интерфейс Throwable. Поэтому catch (Exception $e) перехватит исключения из ветки Exception, но пропустит TypeError.
Если обработчику действительно нужно принимать обе категории, используют catch (Throwable $e). Если требуется обработать только ошибку типов, можно явно указать catch (TypeError $e).
Например, строгая проверка аргумента обнаружила несовместимый тип. Обработчик Exception не сработает, а обработчик TypeError или Throwable — сработает.
При этом Throwable не превращает любой сбой процесса в перехватываемое исключение. И перехват ошибки типов не означает, что её стоит скрыть: часто она указывает на дефект программы, который нужно исправить.
Please open Telegram to view this post
VIEW IN TELEGRAM
www.php.net
PHP: Throwable - Manual
❤3
Представьте, что функция содержит проверку файла, затем yield. Вы обернули только получение генератора в try, а foreach разместили после catch. Если проверка файла выбросит исключение при начале обхода, этот catch его уже не перехватит.
Даже код, записанный до первого yield, относится к отложенному выполнению тела генератора. Чтобы обработать его исключения, нужно охватить try и ту часть программы, которая запускает или продолжает обход.
Но не все ошибки откладываются. Вычисление аргументов и проверка их типов происходят при вызове и могут завершиться ошибкой сразу.
Если проверку нужно выполнить именно в момент вызова, можно вынести её в обычную функцию-обёртку, которая после проверки вернёт генератор.
Please open Telegram to view this post
VIEW IN TELEGRAM
www.php.net
PHP: Generators overview - Manual
В Proglib Academy действует акция: покупаешь один курс, а второй получаешь в подарок.
Например, можно совместить два направления по работе с ИИ:
💥 ИИ для разработчиков — применение нейросетей в повседневной разработке: работа с кодом, тестирование и ревью.💥 Разработка ИИ-агентов — архитектура агентов и создание собственных AI-решений.
А если тебе интереснее Python, алгоритмы, backend или DevOps — выбирай другую пару курсов из каталога.
Акция действует до 31 октября включительно
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱1
Допустим, есть функция findUser(int $userId), а клиент вызывает findUser(userId: 42). Если переименовать параметр в $id, позиционный вызов findUser(42) продолжит работать. Но прежний именованный вызов завершится ошибкой Unknown named parameter $userId, если функция не принимает этот аргумент через вариативный параметр.
Порядок и тип параметра при этом могли вообще не измениться. Ломается именно обращение по старому имени.
Это касается и переопределения методов: язык может разрешать другие имена параметров в реализации, но именованный вызов будет зависеть от фактически выбранного метода.
Поэтому имена параметров публичного API стоит учитывать при оценке обратной совместимости, а не считать их исключительно внутренней деталью.
Please open Telegram to view this post
VIEW IN TELEGRAM
www.php.net
PHP: Function parameters and arguments - Manual
Для ключей 1 и '1' получится один и тот же ключ. Поэтому после присваиваний $data[1] = 'first' и $data['1'] = 'second' в массиве останется одна запись со значением 'second'.
Но не любая числовая строка ведёт себя так. Например, '01' останется строковым ключом из-за ведущего нуля, а '+1' — из-за знака плюс. Они могут существовать отдельно от целочисленного ключа 1.
Это важно, когда ключи приходят извне: идентификаторы, которые выглядят разными по типу, после добавления в массив могут совпасть.
Если нужно различать такие значения, можно явно кодировать ключи с префиксом, например 'int:1' и 'string:1'. Обычный PHP-массив сам по себе различие между ключами 1 и '1' не сохранит.
Please open Telegram to view this post
VIEW IN TELEGRAM
www.php.net
PHP: Arrays - Manual
🔥3🌚1
Переименовывает ли as метод трейта или добавляет второе имя?
Ответ: Добавляет второе имя. Исходный метод при этом остаётся доступным. Через as также можно изменить видимость метода, но сам по себе этот оператор не разрешает конфликт двух одноимённых методов из разных трейтов. Для выбора реализации используют insteadof, а для дополнительного имени — as. Эти операции можно сочетать, чтобы сохранить обе реализации под разными именами.
Документация: конфликты и псевдонимы методов трейтов
Основа вопроса: Hennadii Alforov о вопросах, которые он задаёт PHP-разработчикам.
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Основа вопроса: Hennadii Alforov о вопросах, которые он задаёт PHP-разработчикам.
Please open Telegram to view this post
VIEW IN TELEGRAM
Копируется ли строка на 100 МБ при передаче в функцию по значению?
Ответ: Обычно полная копия сразу не создаётся. PHP использует разделение данных с подсчётом ссылок и механизм copy-on-write. Пока функция только читает строку, несколько переменных могут использовать одни данные. Когда требуется изменить разделяемую строку, создаётся отдельная копия. Поэтому передача по значению не означает немедленного удвоения памяти. Но конкретный расход зависит от операций внутри функции и устройства строки.
Документация: управление памятью и copy-on-write
Источник вопроса: Hennadii Alforov, раздел PHP itself.
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Источник вопроса: Hennadii Alforov, раздел PHP itself.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Чем static-замыкание отличается от обычного при работе с $this?
Ответ: Обычное замыкание, созданное в контексте объекта, автоматически получает привязку к нему через $this. Пока замыкание живёт, эта привязка может удерживать объект в памяти. У static-замыкания автоматической привязки нет, и использовать $this внутри него нельзя. Это полезно, если функция не должна зависеть от экземпляра. Но захват объекта через use всё равно может создать сильную ссылку — слово static этому не мешает.
Документация: анонимные и статические анонимные функции
Основа вопроса: Вопросы Hennadii Alforov о замыканиях и внешнем контексте.
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Основа вопроса: Вопросы Hennadii Alforov о замыканиях и внешнем контексте.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Можно ли объявить private-метод в интерфейсе PHP?
Ответ: Нет. Методы интерфейса должны быть публичными. Интерфейс задаёт контракт, доступный вызывающему коду, а приватный метод является внутренней деталью реализации. Если нескольким классам нужна общая закрытая реализация, её можно разместить в подходящем трейте или базовом классе. Но объявить такой метод приватным членом интерфейса нельзя.
Документация: интерфейсы объектов
Источник вопроса: Hennadii Alforov, раздел PHP itself.
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Источник вопроса: Hennadii Alforov, раздел PHP itself.
Please open Telegram to view this post
VIEW IN TELEGRAM
Может ли class_exists запустить автозагрузку?
Ответ: Да. По умолчанию второй аргумент $autoload равен true. Если класс ещё не загружен, PHP может вызвать зарегистрированные автозагрузчики. Поэтому такая проверка способна выполнить код и загрузить файлы. Если нужно узнать только о наличии уже объявленного класса, передайте false вторым аргументом. Сам объект при этом не создаётся: загрузка определения класса и создание экземпляра — разные действия.
Документация: class_exists
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Please open Telegram to view this post
VIEW IN TELEGRAM
Можно ли подставить имя таблицы через параметр PDO-запроса?
Ответ: Нет. Параметр представляет отдельное значение, например строку или число. Он не заменяет имя таблицы, столбца, ключевое слово или произвольный фрагмент SQL. Поэтому конструкция вида SELECT * FROM :table не решает задачу динамического выбора таблицы. Для идентификаторов используйте заранее разрешённый список вариантов и подходящие правила их оформления для вашей СУБД. Значения условий по-прежнему передавайте параметрами.
Документация: PDO::prepare
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Please open Telegram to view this post
VIEW IN TELEGRAM
Чем persist отличается от flush в Doctrine?
Ответ: persist сообщает EntityManager о новой сущности и включает её в отслеживание. Сам по себе этот вызов не означает немедленный INSERT. Метод flush синхронизирует накопленные изменения с базой данных: создаёт нужные SQL-запросы для отслеживаемых сущностей. При этом flush не равен безусловному завершению любой внешней транзакции — её границы зависят от того, как организована работа с EntityManager и соединением.
Документация: работа с объектами Doctrine
Основа вопроса: Вопросы Hennadii Alforov о Doctrine и Unit of Work.
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Основа вопроса: Вопросы Hennadii Alforov о Doctrine и Unit of Work.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Когда выбрать интерфейс, а когда — абстрактный класс?
Ответ: Интерфейс подходит для общего контракта между разными реализациями. Класс может реализовать несколько интерфейсов. Абстрактный класс нужен, когда участникам одной иерархии требуется общая реализация или состояние. Но наследоваться можно только от одного класса. Не стоит создавать базовый класс лишь ради пары общих методов: иногда проще выделить отдельный объект. В PHP 8.4 интерфейсы также могут задавать требования к свойствам — это не делает их хранилищем состояния экземпляра.
Документация: интерфейсы • Документация: абстрактные классы
Источник вопроса: Hennadii Alforov, раздел PHP itself.
➡️ Навигация: База знаний • Задачи • Собеседования • Вакансии
🐸 Библиотека программиста
Источник вопроса: Hennadii Alforov, раздел PHP itself.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
7 ноября (в эту субботу!) в 15:00 МСК приходи онлайн на открытое собеседование. Посмотришь, как проходит настоящее интервью на Middle PHP-разработчика.
Как это будет:
📂 Глеб Виноградов, Staff Software Engineer в Ad Tyres International, ex-Lead в Bumble, проведёт собес. У Глеба больше 11 лет в разработке. В Bumble он 4 года писал бэкенд для приложений Bumble и Badoo;📂 Глеб задаст реальные вопросы с технических секций и прокомментирует ответы;📂 В конце можно будет задать ему любой вопрос.
Участие бесплатное. Эфир проходит в рамках менторской программы ШОРТКАТ для разработчиков, которые хотят сменить работу, повысить грейд и зарплату или прокачать навыки.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_php_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
Если метод базового класса вызывает self::name(), он выберет реализацию из базового класса. При static::name() вызов через наследника сможет попасть в переопределённый метод наследника.
Используйте static::, когда наследник должен участвовать в выборе реализации. self:: подходит для обращения к реализации класса, в котором расположен код.
Вопрос из подборки для собеседований
Please open Telegram to view this post
VIEW IN TELEGRAM
В блоке use выбирают нужную реализацию через insteadof. Например, A::save insteadof B оставит метод save из трейта A.
Второй метод можно сохранить под дополнительным именем: B::save as saveFromB. Сам по себе as добавляет псевдоним и не решает конфликт исходных имён. Для выбора основного метода всё равно нужен insteadof.
Вопрос из подборки для собеседований
Please open Telegram to view this post
VIEW IN TELEGRAM