Комментарии 19
У меня смешанные чувства.
С одной стороны, я не согласен с теми кто считает, что на Хабре не должно быть статей базового уровня. Любой уровень важен. С другой стороны, как раз про базовые вещи должен писать специалист, а не тот, кто их только что для себя открыл. А здесь автор зачастую явно не понимает смысла написанного.
С одной стороны, видеть на Хабре довольно беспомощный текст довольно непривычно. С другой — ну а где автору еще опыта набираться, фидбек получить?
В общем, если автор переработает статью по результатам обсуждения, то из нее вполне может получиться что-то толковое.
Из ключевых моментов.
- Информация про типы запросов довольно бесполезная. Надо написать хотя бы про http_build_query() и CURLFile. Про последний особенно, поскольку без него использование multipart/form-data не имеет смысла.
- Обработка ошибок. Всё плохо, сплошной кринж и карго-культ. Начиная с вступления, которое явно бездумно переписано с какого-то мусорного источника.
- "В основном, это ошибки на стороне сервера" — шта? Какой сервер имеется в виду? Удалённый? Видимо, нет, хотя по логике должен быть именно удаленный, раз мы говорим о curl. Но если локальный, то снова вопрос — о каких конкретно исключениях речь? Вроде бы, тут только обращения к функциям curl, но они исключений не бросают.
- Сам текст исключений — классическая ученическая бессмыслица. Видно, что человек ни разу не был в ситуации, когда ему надо отладить курл запрос, и пишет просто от балды, "шоб було". "Запрос не был успешен" — а как конкретно он был неуспешен? Какой конкретно код вернулся? 4хх? 5хх? 204? А это точно неуспешный запрос? Какой был актуальный ответ сервера? Не знаем, мы его убили поспешным декодированием.
- проверка результата декодирования json — один сплошой кринж. Зачем там
is_object($data)
? Почему мы принимаем только массивы? А если сервер вернул булево значение или строку? Зачем вообще так криво проверять корректность декодирования, если в json_decode это делается СОВСЕМ по-другому, либо через json_last_error(), либо — предпочтительнее — через выброс исключения самой функцией - зачем здесь вообще раскодирование JSON? А если мы запрашиваем HTML? XML? Картинку? Каждая функция должна делать что-то одно. Функция для работы с curl должна возвращать полученный ответ. А как его декодировать, и декодировать ли вообще — не ее ума дело. И в итоге получается, что ни исключения, ни try-catch нам тут по сути и не нужны.
- "Стоит отметить, что URL-адреса "http" не имеют SSL-сертификата для проверки, поэтому установка этой константы в значение true приведет к неудачному запросу" — мягко говоря, не совсем true. А вот CURLOPT_FOLLOWLOCATION как раз следовало включить в список основных констант.
В итоге пример должен получиться примерно таким
// Определение параметров запроса
$CurlOptions = [
CURLOPT_URL => 'http://domain-name/endpoint-path',
CURLOPT_POST => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_HTTPHEADER => array( 'Content-Type' => 'application/json' ),
CURLOPT_POSTFIELDS => $json_data,
];
// Инициализация запроса
$ch = curl_init();
// установка параметров сеанса
curl_setopt_array( $ch, $CurlOptions );
// Выполнение запроса, в переменной хранится ответ от сервера
$data = curl_exec($ch);
$info = curl_getinfo($ch);
if (curl_errno($ch) || substr($info['http_code'],0,1) !== '2') {
// обработка ошибки,
// желательно пользовательским исключением,
// у которого есть свойства для $data и $info
var_export(curl_error($ch));
var_export($data);
var_export($info);
}
При этом лишний раз напомню, ни для того, чтобы РНР выбросил исключение, ни для того чтобы прочитать текст ошибки выброшенного исключения, писать try… catch не надо! Этот оператор следует применять очень редко, и только когда мы точно знаем, как именно будем обрабатывать исключение.
"try...catch нужно применять очень редко" - это очень спорное утверждение. Как раз в большинстве случаев исключение надо обрабатывать. В реальном проекте большинство случаев будет обрабатывать фреймворк, но это значит только то, что кто-то за вас сделал эту работу, а на самом то деле под капотом надо красиво логировать исключения, возвращать правильный код статуса, может красивы стэк трейс на экран вывести итп.
Вы совершенно правы, исключения надо обрабатывать. Вот только пихать везде try...catch к нормальной обработке исключений не имеет ни малейшего отношения.
Вот вы сами над своими словами задумайтесь:
надо красиво логировать исключения, возвращать правильный код статуса, может красивы стэк трейс на экран вывести итп
— и все это — внутри try...catch? Каждого? ;-)
Я лишь привел пример того, что надо будет делать с исключением. Есть огромное количество примеров, когда обрабатывать исключение надо немедленно в том самом месте, где оно выброшено. Для логирование и стэк трейса конечно можно гораздо выше по стеку вызовов, но обернуть ошибку валидации, например, с указанием причины ошибки надо немедленно, пока у нас есть доступ к контексту валидации. Ошибки типа деления на ноль тоже необходимо оборачивать немедленно, пока в самом коде можно понять, что где и почему выбрасывает исключение, а не искать все это в стек трейсе. И таких примеров очень много, и даже сам php предусматривает механизм добавления новой информации на каждом уровне стека вызовов через передачу текущего исключения в конструктор нового через параметр previous, что мы активно в наших проектах используем для того, чтобы в каждом архитектурном слое добавить информации из контекста. Условный пример: пользователю не интересно видеть исключение от доктрины NoResultException. В рамках symfony/laravel это надо обернуть в HttpNotFoundException, который в свою очередь будет пойман фреймворком и обернут в html с 404 ошибкой или в соответствующий json. Пример очень простой, но если не вдаваться в детали, то примерно такой подход мы используем в наших проектах с многослойными архитектурами
Вы привели очень кривой пример того, что надо будет делать с исключением. Классическую похапешную бессмыслицу.
Давайте я повторю ещё раз: "чтобы логировать исключения, возвращать правильный код статуса, может красивы стэк трейс на экран вывести" трай кетч писать не надо.
Новые примеры уже ближе к реальности.
Но если дать себе труд подумать, то окажется, что исключение либо вообще не нужно, либо его можно точно так же обработать централизованно, без замусоривания кода бессмысленными try...catch.
"Исключение с ошибкой валидации" — это бессмыслица, оксюморон. Исключение может возникнуть, если функция, которая уже использует данные, не может этого сделать. То есть, не может выполнить свою функцию. А при валидации возникает не ошибка, а собственно результат — валидные данные, или нет. Поскольку валидация и является функцией функции. И выбрасывать исключение она будет только если не может провалидировать данные. Но не тогда, когда может, и видит, что они не валидные.
Вообще, рассуждая о ловле исключений, приучайтесь всегда упоминать конкретный сценарий обработки. Потому что поймать исключение много ума не надо. Но вот написать в catch что-то осмысленное получается далеко не всегда. Вот вы пишете, "Ошибки типа деления на ноль тоже необходимо оборачивать" — и? Что делать с ними? Где эта ошибка? В модели? В контроллере? Как ее обрабатывать? Следует ли любую операцию деления оборачивать? Без ответов на все эти вопросы разговор получается пустой.
По поводу конверсии в HTTP исключения у меня есть готовый рецепт, вот неплохая идея: Centralized exception handling with Symfony and custom PHP attributes. Все-таки, ходить за каждым исключением с трай-кетчем, как за слоном с лопатой — это как-то совсем по-деревенски. Программисты мы, или нет, в конце концов? Зачем вообще тогда париться с исключениями? Сделать по-старинке, проверку результата функции на false. И замусоривать код проверками на каждый чих.
Исключения придуманы, чтобы сделать код чище, а не чтобы постоянно спотыкаться об try..catch.
Случаи, когда нужно поймать исключение действительно бывают. Но далеко не так часто, как это делают начинающие программисты, с их вечным "стэк трейс на экран вывести". Сказать "исключение надо обрабатывать!" любой дурак может. Но вот написать в catch что-то осмысленное куда сложнее. И любой разговор надо начинать именно с этого — с кода, который мы собираемся писать для обработки.
Спасибо за комментарий! Немного поправил статью. На большее пока, к сожалению, нет ресурса.
@FanatPHP Во-первых, по поводу исключений с ошибкой валидаций: laravel кидает исключение, ктторое мапится на 429 уод http при ошибке валидации. Это норма.
Во-вторых, по поводу стек трейсов, логирования итп. Лично ВАМ этого делать не надо, потому что используя фреймворк, кто-то за ВАС уже это сделал. Это не значит, что теперь вам об исключениях не надо заботиться. Как только вы изолируетесь от фреймворков, или используете минималистичные фреймворки, это становится ВАШЕЙ проблемой. Это как раз случай автора.
В-третьих, по поводу вашего решения. У меня при прочтении возникало только одно слово в голове: "зачем?!"(в оригинале грубее). Вы напрочь игнорируете принцип KISS, и вы напрочь игнорируете существующие решения. Ваше решение в отличии даже от первого варианта выглядит проигрышнее по 2ум причинам: 1) ваше решение актуально только для симфони, в то время как первое решение с обычным try с несколькими блоками catch работает везде и всегда 2) первое решение максимально простое, если не сказать что тупое, его поймет любой джун. Но если вас смущает, что в блоках catch почти одинаковый код, то для вас есть простое решение: из вашего решения выкидываете все, кроме интерфейса StatusCodeProvider, наследуете его от Throwable, что автоматически обяжет пользовательское исключение наследовать Exception или Error, а затем вместо нескольких catch блоков использовать один, который ловит StatusCodeProvider. Это если придумываете велосипед. В симфони просто реализуйте интерфейс HttpExceptionInterface, остальное за вас сделает фреймворк. К чему эта магия с глобальным перехватчиком ивентов симфони, рефлексией и атрибутами? Это называется Overengineered garbage code: вы решаете очень простую задачу каким-то хитровыдуманным способом. Нафига?! Вы любите острые ощущения в продакшене?
Исключения действительно нужны для чистоты кода, но ваше решение - это прямая противоположность чистоте кода. Чистый код в первую очередь - это понятный каждому код, выполняющий четко свою задачу. Для простой задачи вы придумываете магическое решение, которое решается намного проще, если не пытаться ничего выдумывать. Не усложняйте жизнь себе и вашим коллегам.
Мне кажется, вы опять запутались, и вернулись к своему первому комментарию.
по поводу стек трейсов, логирования итп. Лично ВАМ этого делать не надо
Давайте постараемся запомнить две вещи:
- Здесь никто здесь не говорит, что исключения вообще обрабатывать не надо.
- Что натыкивание try..catch по всему коду не является единственным способом обработки исключений.
"стек трейсов, логирования итп." — вещи очень нужные, и мне в том числе. Я говорю, уже в который раз, не об этом. А том, что использовать для этого try-catch — глупость. С этим прекрасно справляется централизованный обработчик ошибок. И давайте уже не будем поднимать эту тему, хорошо?
Это как раз случай автора.
Нас не интересует случай автора. Код, в любом случае, будет один и тот же. Работа с курлом — это как раз один из примеров, когда использование try-catch вполне может понадобиться. К примеру, если просрочился токен авторизации, и надо запросить новый. Или чтобы сделать небольшую систему обработки отказов, повторяя при некоторых ошибках запрос несколько раз.
Но при этом надо понимать, что в любом случае бросок исключения не завязан на его обработку. А у вас, похоже, эти понятия так в голове перемешались, что вы просто не различаете, что это, вообще-то, две разные, никак не связанные друг с другом задачи. В общем случае код должен просто кинуть исключение, и не думать о том, кто и как его будет ловить. Вот это и есть "случай автора". Код бросает исключение, и дальше все будет зависеть от потребностей и инфраструктуры. На начальном этапе разработки исключение будет вываливаться на экран, ближе к выкатке появится централизованный обработчик ошибок, который, в зависимости о окружения, будет показывать либо красивы стэк трейс, либо красиво логировать и возвращать HTML/JSON для 500. При этом сам код функции не поменяется.
Дальше автор может захотеть систему обработки отказов, и обернуть вызов этой функции в try-catch, который проверяет тип ошибки, и если она подходит под определенные условия, то через небольшой таймаут пытается сделать запрос снова. А если не подходит под условия, то исключение перевыбрасывается, и ловится уже либо централизованным обработчиком, либо где-то еще. При этом сам код функции снова не поменялся. А сейчас у автора обработка исключения вкрячена прямо в код функции выполнения запроса, что, конечно же, никуда не годится. И я очень надеюсь, что вы с этим согласитесь.
По поводу "моего" решения. Я не настаиваю, что оно лучшее. Это просто один из примеров того, что механического натыкивания try-catch и ручной конвертации исключений можно вполне избежать. И если присмотреться к своему коду, то выяснится, что такое решение найдется для всех массовых вариантов использования try-catch, в которых, как вы правильно заметили, "почти одинаковый код".
С этим прекрасно справляется централизованный обработчик ошибок
Для того, чтобы у вас был централизованный обработчик ошибок, вы должны написать его или воспользоваться готовым решением. Возможно я открою вам тайну, но симфони позволяет выкидывать ненужные компоненты
Нас не интересует случай автора.
С него все и началось, поэтому глупо от него отмахиваться. Такое ощущение, что вам просто не хватит аргументов, чтобы поспорить с тем, что данные пример - наглядное доказательство того, о чем я говорю
бросок исключения не завязан на его обработку
Какая глупость... Да будет вам известно, что исключение - это такой же легальный возврат из функции, как и return. Бывают случаи, когда вам возвращаемое значение из функции не нужно, но таких случаев единицы. Если исключение кидать, если его не надо обрабатывать или случаев, когда его надо обработать очень мало? Проще уже самому исключительные случаи предусмотреть и не кидать исключение. Наверное его кидают, потому что вариантов обработки, как и случаев, когда это действительно нужно много, и проще отдать это на усмотрение пользователю. С исключениями то же самое, что и возвращаемым значением: в единицах случаев нам надо не ловить исключение, чтобы уронить скрипт. В чуть большем количестве случаев можно обойтись глобальным перехватчиком. В остальных случаях нам почти всегда исключения надо ловить и правильно обрабатывать. Может не прямо в месте вызова функции, а на несколько уровней выше, но ловить надо, иначе у вас будут странности, типа того, что я порой вижу как на некоторых сайтах с упавшей базой прямо в браузер кидается PDOException
По поводу "моего" решения. Я не настаиваю, что оно лучшее. Это просто один из примеров того, что механического натыкивания try-catch и ручной конвертации исключений можно вполне избежать.
Такое решение не должно быть в пользовательском коде, потому что вы решаете простую задачу сложным путем. Помимо этого магия с атрибутами и рефлексией... Вместо слов, стоит процитировать 2 поговорки из Zen of Go: Clear is better then clever, Reflection is never clear. Максимально тупое, в хорошем смысле, решение всегда выигрышнее: оно понятно любому джуну, и вам не нужно будет тратить часы на объяснение того, каким образом работает решение подобно вашему. С более опытными разработчиками вы тоже потратите часы, но на объяснение причины того, почему так
Мда, ну у вас и каша в голове :)
Вы мне напоминаете Буратино из сказки, с его упрямиством и эээ… прямолинейностью. Помните?
— Предположим, что у вас в кармане два яблока. Некто взял у вас одно яблоко. Сколько у вас осталось яблок?
— Два.
— Подумайте хорошенько. Буратино сморщился, — так здорово подумал.
— Два… — Почему?>
— Я же не отдам Некту яблоко, хоть он дерись!
Вы смотрите на вещи очень буквально, и никак не можете абстрагироваться от прямолинейного отношения к исключениям, как к банальным ошибкам.
Для того, чтобы у вас был централизованный обработчик ошибок, вы должны написать
Должен, должен. Разговор не об этом. А про try..catch. Который не должен использоваться для репортинга ошибок. Если у вас еще нету централизованного обработчика, это не повод пихать везде трай с кетчем. Понимаете? Это же будет двойная работа, сначала писать его на каждый чих, а потом выковыривать, когда появится глобальный.
глупо от него отмахиваться
Вы опять ничего не поняли :)
Случай автора нас не интересует, потому что он нам не принципиален. Он ничем не отличается от любого другого случая выброса исключения. И точно так же, как и в любом другом случае, связав его трай кетчем вы тут же ограничили себя в вариантах обработки.
Да будет вам известно, что исключение — это такой же легальный возврат из функции, как и return.
Здесь у вас совсем логика захромала :(
Да, легальный. Но из этого никак не следует, что любую функцию надо оборачивать в трай-кетч! Ну неужели это непонятно? Исключение тем и отличается от возврата, что поймать его можно где угодно.
в единицах случаев нам надо не ловить исключение, чтобы уронить скрипт. В чуть большем количестве случаев можно обойтись глобальным перехватчиком.
И здесь :(
Вы правда не понимаете, что это одно и то же?
прямо в браузер кидается PDOException
И здесь :(
Уж это-то никаким боком не имеет отношения к обработке исключений.
Если прямо в браузер кидается ошибка, то это значит, что на сервере криво настроено отображение ошибок. И исправлять надо именно это. А исключения обрабатывать обычным порядком. Ошибки PDO как раз относятся, за небольшим исключением, к тем самым исключениям, которые "роняют скрипт". И ничего глупее, чем заворачивать каждый запрос в трай кетч (чтобы предотвратить отображение ошибки в браузер) придумать невозможно. И я просто счастлив, что с моей подачи в мануале начали наконец-то показывать нормальную работу с ошибками, а не эти вездесущие трайкетчи. Хотя конечно за столько лет эти примеры попортили немало неокрепших умов. Но если сейчас посмотреть на примеры для работы с PDO, то там этого мусора становится все меньше.
И вы тоже не отставайте, идите в ногу со временем. Смотрите на исключения не как на банальные ошибки, а как на гораздо более гибкий и удобный механизм, который в большинстве случаев не требует немедленной проверки результата :)
Вы смотрите на вещи очень буквально, и никак не можете абстрагироваться от прямолинейного отношения к исключениям, как к банальным ошибкам.
Вы совершаете типичную ошибку: исключения != ошибка. В php к сожалению разница между Exception и Error условная. Но в других языках это не так. Именно ошибки ловить не стоит, а в других языках это вообще невозможно, потому что они действительно нужны чтобы просто уронить программу, но речь то про исключения, а исключения != ошибки. Вы же их мешаете в своих утверждениях. Пример исключения: передача 0 в делитель, потому что операция деления принимает 2 числовых операнда, но есть 1 случай, когда деление не сработает. Пример ошибки: передача строки в операцию деления, потому что деление работает только с числами. То, что php позволяет ловить и ошибки, и исключения - это, имхо, большое упущение, поэтому надеяться можно только на линтеры и code review.
Он ничем не отличается от любого другого случая выброса исключения.
Он отличается тем, о чем я вам твержу уже несколько комментариев: это случай, когда у вас нет глобального обработчика исключений
Исключение тем и отличается от возврата, что поймать его можно где угодно.
Опять же, разница исключений и ошибок: исключения стоит ловить сразу. Зачем мне на уровне контроллера оборачивать метод, в котором через несколько слоев есть вызов метода из доменного слоя, в котором есть деление и потенциально там может быть деление на 0? Нет, надо ловить исключение сразу. При чем возможно ловить его в самом доменном слое, а затем оборачивать в исключения доменного уровня.
Если прямо в браузер кидается ошибка, то это значит, что на сервере криво настроено отображение ошибок.
Опять же путаются исключения с ошибками. Я не знаю, что у вас за принципы, но даже если настроить отображение ошибок правильно, то вы просто ошибку замаскируете под статус код 500, чего пользователь в нормальном сервисе видеть никогда не должен.
Смотрите на исключения не как на банальные ошибки
В том то и дело, что как на ошибки смотрите на исключения вы. Вы же их мешаете в своих утверждениях, хотя это разные вещи, пусть и технически в php они практически не отличаются
Вы так восхитительно боретесь с ветряными мельницами :)
Он отличается тем, о чем я вам твержу уже несколько комментариев: это случай, когда у вас нет глобального обработчика исключений
Вот это как раз хороший пример того самого ограничения, которые вы себе выдумали, как буратина своего Некту, и отчаянно с ним деретесь :)
Сначала ваш воображаемый Некто предлагал вообще не обрабатывать исключения, и вы на него с пылом наскакивали. Хотя с вами никто не спорил. Теперь вот он отказывается делать глобальный обработчик ошибок. Вопрос — кто ему мешает-то?
Вы правда не понимаете, что сейчас глупость говорите? Ну просто если включить банальный здравый смысл, то если у нас нет глобального обработчика ошибок,
- Кто нам мешает его сделать?
- Почему вместо того, чтобы его сделать, вы предлагаете на каждый чих писать кучу трай-кетчей? Вот это я никак не могу понять. И просто логически, но — главное — потому что в принципе невозможно каждую строчку, которая может выкинуть исключение, обернуть в трай-кетч. И у вас все равно будут неотловленные исключения. За что боролись, называется :)
Или вот ещё из той же серии
если настроить отображение ошибок правильно, то вы просто ошибку замаскируете под статус код 500, чего пользователь в нормальном сервисе видеть никогда не должен.
Ну вот с чего вы это взяли-то? Во-первых, это не я путаю ошибки с исключениями, а РНР. Неотловленное исключение превращается в ошибку. Т.е. "задача сводится к предыдущей" :)
А во-вторых, мы точно говорим о "правильной настройке отображения ошибок"? При правильной клиент получит HTML/JSON вариант 500 ошибки, как и положено. Что здесь-то вам не так?
В целом, у меня к вам только одна просьба. Давайте не будем углубляться в дискуссию error vs. exception. Хотя там действительно можно провести несколько вариантов разделения, как формальных, типа warning/fatal error vs exception или Exception exception vs Error exception, так и неформальных, типа Control flow exceptions vs. Error exceptions, но все эти разделения довольно условны и не имеют прямого отношения к нашему вопросу. Не говоря уже про ваше, высосанное из пальца, при котором внезапно DivisionByZeroError это "исключение", а TypeError — уже "ошибка" :)
Автору:
расматриваются базовые (очень базовые) возможности курла. При чём здесь пхп?
если пхп "при чём", то где curl_multi_init? Это же чуть ли не единственный способ распарралелить однопоточный пхп без использования event loop'ов.
если пхп "при чём", то где Guzzle? Лично мне он не очень-то нравится интерфейсной частью, но архитектурно он вполне хорош. И он работает.
Вышеотписавшимся комментаторам:
каждому слою - свой эксепшен. Если на "верх" прилетает эксепшен от инфраструктуры -- у вас проблемы с архитектурой.
за сигнатуру
Response | flase
надо изгонять из общества. Даже похапешное ядро отказывается от этого.
Видимо, пхп тут при том, что статья про php-curl и все примеры даются на PHP? Этак вы будете капризничать, если вам про mysqli будут рассказывать, под тем предлогом, что это обертка над Mysql API.
Статья откровенно слабая, это правда. Но ваши придирки как-то совсем не в тему. Это описание начинающим своего опыта с php-curl. Она имеет прямое отношение к РНР. Про Guzzle и curl_multi он не слышал. Упомянуть их, возможно, и стоило, но только вскользь. Потому что это именно что про "очень базовые возможности курла". Да, статьи про базовые возможности тоже нужны. Как и про небазовые. Просто это два разных типа статей, и их не надо смешивать.
mysqli
разве не deprecated? Новость.
Я по-дефолту плюсую статьи про пхп, просто потому что сейчас процентов 80 времени пишу на нём. Но поверхностное описание сишной либы, даже если примеры даны на пхп, не делают это статьёй про пхп.
Давайте лучше про ексепшены поговорим?
Вообще-то нет, mysqli не deprecated. Для меня новость, что для кого-то это новость :)
У вас какое-то странное представление о РНР. Давайте я вам еще одну новость сообщу: 50% РНР — это тончайшие обертки над системными библиотеками/вендорскими API. От strtotime и тех же mysqli с курлом до imagick и OpenSSL. Повторюсь: если так капризничать, то про половину функций РНР писать будет нельзя, поскольку это будет "поверхностное описание сишной либы" :)
Давайте все-таки попустимся немного, и договоримся, что если в РНР есть какой-то функционал, то писать про него можно, не оглядываясь на то, лежит под ним какая-то "сишная либа", или нет :)
Вот про исключения я с вами в целом согласен. Каждому слою — свой эксепшен. Это осмысленная позиция. Она не противоречит моей, которая заключается в том, что обработка исключения должна быть абстрагирована от его выброса. А не жестко на него завязана, как предлагает коллега выше. "Танцуй, как будто никто не видит, бросай, как будто никто не ловит".
Вообще-то нет, mysqli не deprecated. Для меня новость, что для кого-то это новость :)
Спасибо. Видимо, это это была ложная память.
У вас какое-то странное представление о РНР
Нормальное представление, в сорцах ориентируюсь довольно свободно. Кроме поддержки utf. Лол. Три-четыре уровня макросов, пока доберёшься до кода, уже забудешь, зачем пришёл.
Ой, простите. Не utf, конечно.
I18N
Верю, и уважаю. Сам я в сорцах "читаю со словарем".
Но все же, если вернуться к вопросу о "системных либах".
Если вам не нравится mysqli (хотя она к 8.2 по функционалу практически догнала PDO, в ней нет только именованных плейсхолдеров, а кое в чем и обогнала), давайте возьмем php-pgsql. Тоже ведь все построено вокруг системной либы, тончайшая обертка над Postgres C API. Это же не повод не писать статьи о том, как правильно пользоваться. Как раз наоборот, писать надо. Потому что нормальных материалов по ванильному РНР практически нет. Есть только типичный ад из прошлого века, со всем этим catch (PDOException $e) { echo$e->errorMessage(); }
и проч.
Ведь просто знать набор функций мало. Надо еще и с умом их применять. Вот взять хотя бы бессмысленные исключения, которые автор кидал в исходном варианте статьи, а потом тупо выводил. То есть вполне можно было обойтись die("Запрос не был успешен");
с тем же самым результатом.
Или другой пример: в другой системной либе есть функция mysql_real_escape_string(). Сколько РНР сайтов светили и до сих пор светят инъекциями только потому что средний пхешник просто не понимает, для чего эта функция нужна и как ее применять? И таких примеров миллион. Так что статьи по правильному использованию "системных либ" нужны обязательно. Надеюсь, я вас убедил :)
Основы библиотеки cURL PHP