• Как обойти большой json файл и обновить все связанные записи в MySQL, с отставанием от файла < 2 сек.?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Сначала если есть возможность менять парсер - убери json
    Его считывают в память целиком, его нельзя "прочитать построчно" с помощью итератора двигаясь по файлу считывая по 1 строке

    Похоже у тебя реализована очередь, но только своя. Может быть взять очередь (приспособить редис, там есть простенькие очереди в комплекте - или посмотреть какие еще очереди бывают - там их десяток помоему), чтобы задачи валились в список, а второй скрипт разгребал список, запускаясь по времени или когда очередь начнет выполнять задачу, а не висел в памяти и while (true) ждал пока ему скажут "работай"...

    Яндекс решает задачу аналитики кто куда чего кликнул именно очередями, сбрасывая "отставание" с "2 секунды" до "какая мне разница, как проц освободится, так и сделаем" - да задачи начинают обрабатываться последовательно, а не параллельно.

    Ещё можешь свой скрипт на ноде написать, там асинхронка может помочь. или сделать с помощью
    new class extends \Threaded подключив расширение pthreads.so/.dll

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

    Но учитывай, что запись и обновление в SQL все равно ставится в очередь, так что предел скорости присутствует
    Ответ написан
    2 комментария
  • Как выборочно удалить устаревшие кэшированные результаты из базы данных?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Именно так, инвалидация кеша довольно "весёлое" занятие.
    Немного упрощает работу с этим на мой взгляд группировка кешей - это когда кеш хранится не просто в файле или редисе с ключем в виде хеша, а когда он хранится типа такой строкой "models.users.find.city", еще я юзаю бывает константу __METHOD__ магическую - там неймспейс сразу есть (хотя это годится в основном для будущей ручной очистки, чем для автоудаления), осталось примесь добавить в виде параметров под юзера, кстати эта примесь тоже может например base64 стать потом и служить ключем (user:1 -> base64) и потом найти запись где есть такой-то base64. По крайней мере ты получаешь возможность найти все кеши связанные с city и их снести руками.

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

    Опять же есть колхоз на тему сохрани номер сотни пользователя для 912-го - девять. И снеси сотню кешей например. Или тысячу. Всяко лучше чем 100%. Ну и конечно подумать над необходимостью кешировать данные юзеров. Может есть возможность кешировать только неизменяемую часть. Или не кешировать вовсе то, что юзеры постоянно меняют.

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

    Чем больше тегов - тем менее эффективный кеш и больше занятой памяти на хранение одинаковых вещей, но в то же время тем проще его точечно найти и снести. С другой стороны чем больше слушателей даже очень простых - тем больше система хочет превратиться в шину сообщений (черт ногу сломает какой слушатель что делает и поскольку логи анализируются потом вручную - то здравствуйте "что-то сломалось") и заставить тебя написать сагу.

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

    Но наверняка кто-нибудь знает как проще.
    Ответ написан
  • Автоматически задать новое свойство через setter?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Намекну что лучше не привыкать учить модель делать то, что она не умеет, потому что она и без того в ларавеле несёт бешенный функционал, а написать свой класс в который класть модель на вход и в конструкторе заполнять данными из неё. И там это свойство сделать и другие модули опереть уже на свой класс, который ничего кроме взять-положить не умеет. Потому что такой лишенный функционала класс можно без проблем оставить навечно, т.к. он всегда будет выполнять задачу "дать-взять", в отличии от модели ларавеля которая умеет слишком много и отказ от неё будет означать мозговой штурм и попытки залепить получившиеся дыры скотчем

    Но если прямо очень хочется модель то прям вот так и сделай

    protected $appends = ['created_at2'];
    getCreatedAt2Attribute() {}

    если нужно чтобы сохранялось в базу - нужно записать в массив $this->attributes[ $name ] = $value; потом вызвать save();
    Ответ написан
  • Вывести значение модели Laravel?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Дядь если ты делаешь вызов first то иногда он возвращает null, привыкни писать проверку типа через двоеточие. Код сам станет красивым когда поймешь насколько это мощная штука.

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

    А еще коммент лайкс вероятно возвращающее массив ты отнимаешь из него... Цифру. Оно хорошо что вообще работает
    Ответ написан
  • Как упростить PHP цикл?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Пишу с телефона извините

    Total = 10000
    Max = 200
    While (0 < (total -= (limit = max))) {
    While (limit--) {}
    }

    Если мы говорим о том что там предел по времени типа не больше 200 в минуту, все усложняется малость, тк скрипт будет уже консольный и нужен счетчик и время от времени опрос сколько осталось, ожидалка, вероятно очередь или постановка задач на следующую минуту
    Ответ написан
    Комментировать
  • Можно ли получить данные с сервера, имитировав post запрос?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Просто помни об уголовной ответственности

    С нижеизложенным я сражался - имел прецеденты и писал защиты.

    1. Покупаешь прокси или пишешь парсер проксей (понадобится безголовый браузер)
    2. Пишешь обертку чтобы CURL автоматически проверял и менял прокси более менее разумно или всегда
    3. Открываешь сайт и панель Ф12 - там вкладка Network. Пробуешь купить (даже если денег нет, но кнопка купить есть). Смотришь что на сервер отправляется. Может банально кто-то цену зашил в запрос, хотя это совсем глупая ошибка. Бывает прикол что зачисляешь деньги на сайт, делаешь заказ, потом заказ отменяешь, а отмена написана криво и требует 2 секунды времени. За эти две секунды скриптом можно 1000 раз отменить заказ и получить 1000 возвратов
    4. Смотришь в режиме где потыкать, что поменять. В идеале найти чувака который уже покупал и на боевом посмотреть как процесс происходит
    5. Дальше уже начинаешь играть в иньекции и взлом, в поля форм пхаешь sql - закрывающие кавычки, точки с запятыми. Пытаешься вызвать Critical mysql error. Если получилось - наощуп танцуешь от этого. Если нет - пытаешься яваскрипт код сунуть в формы, но там где есть форма комментариев например, код должен отсылать тебе куки других посетителей, чтобы ты успел под их именем зайти пока сессия не устарела и за их счёт купить

    Но уже много лет как от всего этого написаны защиты. И программистов держат на работе чтобы таких приколов не было.

    Процесс на самом деле не из весёлых и не легкий ни разу, бывает проще найти владельца и убедить его тебе дать, чем без его ведома ломануть его сайт. Но иногда везёт
    Ответ написан
  • Как написать поиск по базе данных?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Оттолкнуться от того что пользователь может передать (порядок важен везде, как задали - так и ищем)

    - фильтры (как правило массив критериев [ [ 'hello', 'like', 'world*' ], [ 'item', '>', 100 ] ])
    -- фильтры типа И/ИЛИ/НЕ - как правило отправляются в один уровень, либо вложенным массивом с ключами [ y => [filter,filter], n => [ y => [filter, filter], 'n' => [ filter ] ];
    - сортировку (как правило массив из массивов [ [ 'hello', 'asc' ], [ 'item', 'desc' ] ]
    - лимит записей
    - отступ от начала таблицы
    - номер страницы (отступ = лимит умножить на (номер-1))

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

    Потом написать обертку которая преобразует входящий GET запрос из массива в некий объект который знает про все вышеперечисленное чтобы дальше его передавать.

    Дальше этот объект передается в некий класс, который умеет искать по источнику данных. Репозиторий. И там делаются функции findByCriteria(Criteria $criteria) во все источники данных - где-то в апишку, где-то в базу, где-то в одну таблицу, где-то в другую.

    Задачка которую решает каждый разработчик на ПХП. А единого решения так и нет.
    Причем это не разу не легкая задачка если её видеть в том виде как автор написал.
    Если задача просто из таблицы по условию выдрать - то она упрощается. Не в 2 раза. А в сто-два.

    У архитекторов конечно есть. Иначе они бы не считали себя архитекторами. Но тебе они не дадут. Иначе ты тоже станешь архитектором, а так нельзя.
    Ответ написан
    2 комментария
  • Как реализовать свой абстрактный класс коллекции?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Коллекция это просто пачка. Массив с цифровыми ключами. Бывает двух типов я для себя назвал - массив и список.
    Массив - ключи строго цифровые и строго по порядку.
    Список - ключи строго цифровые но могут идти не по порядку и некоторые из них могут отсутствовать

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

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

    Почему в Ларавеле коллекции? Потому что им надоело прокидывать по ссылке вероятно и писать методы для работы над массивами. Может не смогли разобраться. Может задолбались. Но под капотом эта их штука спамит коллекциями так что страшно думать. $collection->merge() - мы вроде как с обьектами работаем, а значит должно добавить в нашу коллекцию. Но вместо этого она создает вторую коллекцию, а первую - удаляет, чтобы вести себя так, как это было бы с двумя массивами.

    Вот в Ларавеле получается с этим дичь - они начали юзать обьекты, а потом пытаться реализовать поведение по-старинке, как в массивах. И для чего им теперь эта коллекция кроме как для проверки что она такого-то типа - непонятно.

    Да и сама эта проверка в общем случае нужна в одном двух местах во всей программе. Самое прикольное, что в коллекцию определенного типа на ларе можно подложить модель другого типа и всё заработает. То есть они даже это не использовали.
    Ответ написан
    Комментировать
  • Почему, кроме того что "кто-то там уже придумал" рекомендуют под каждый эксепшен писать отдельный класс?

    gzhegow
    @gzhegow Автор вопроса
    aka "ОбнимиБизнесмена"
    Похоже нашел некоторый удобный способ их применять. Опишу здесь, если кому пригодится.

    Во первых там стандарт есть какой-то PSR где есть 8 классов "опасности" ошибок. Но когда я вижу классификацию на 8 типов, то выглядит это как "на всякий случай сделаем" - человек не способен делить что-то на 8 типов, он в голове держит не более 7 вещей (и это очень прокачанный - 7 вещей). Определить - какая именно из 8 типов ошибка та, которая сейчас пришла в голову для меня - невозможно. Может кто-нибудь в книжке написал, но в жизни думаю он так не делает.

    Если ошибки можно поделить на 8 степеней, то речь здесь не в степенях а в приоритете. То есть \SplPriorityQueue с цифрой приоритета, который в случае чего можно всегда поменять, и посмотреть разницу в статистике за период времени. В данном случае 8 типов означают что-то вроде цветовых маркеров на производстве - "откройте красный ящик, переложите вещи в синий ящик", только без раскраски, но в общем случае 8 для однозначного определения - слишком много, а для статистики - достаточно, хотя в то же время и нет.

    Делим возникающие косяки на:
    1. уведомление разработчика, что программа кривая и так не должно было быть
    2. уведомление/перенаправление пользователя
    3. оповещение других модулей в соседних папках о том, что случилось что-то, что они могли бы решить, но в одиночку никак

    В первую группу в основном падают стандартные эксепшены. Пишем мы функцию
    function a() : int
    {
      return 'vasia';
    }

    Функия возвращает не то, что просили. Об этом должен узнать разработчик, который делает на базе вашего кода. Программа не должна запуститься. Удобный способ делать такие проверки, писать следующий код:
    function verifyEmail($email) : ? string
    {
      if (filter_var($email, FILTER_VALIDATE_EMAIL)) return null;
      return __FUNCTION__ . ' fails: ' . $email;
    }
    // ... code
    if ($err = verifyEmail(123)) throw new \UnexpectedValueException($err);

    Мы возвращаем текст ошибки если проверка не прошла, валидируем.
    Так, например, можно сделать проверку входных параметров на собственный тип не занимаясь ООП ересью на зашивание проверки в конструктор и разбивание массива на свойства, каждое из которых сеттер с валидатором и тд. минус файл и куча логики. Эти ошибки бывают что требуют вывода дополнительной информации в трейс. А поскольку эксепшен не принимает данные дополнительным параметром, я рекомендую дописать функционал `public function data(array $data))` и в особых случаях вызывать throw (new MyException($err))->data($data); и тогда в логах можно добавить эту самую $data не прибегая к танцем с бубном. Она врядли понадобится системному администратору или девопсу, но она точно понадобится тому, кто пойдёт ошибку править. Опять же - в эксепшене есть дерево вызовов и там есть аргументы. Но пару раз по причинам мне непонятным - пыха оставляет там не всё, что я ожидаю там прочитать. В той же валидации аргументом прилетает одна строка, если вывести все дерево - лог будет слишком огромный. А если одну строку - то это ничего не скажет. Чтобы понять, почему валидация сломалась часто нужно увидеть весь входной словарь данных.

    Во вторую группу я отнес ошибки HTTP приложения, приложения как штуки способной принимать команды и отвечать на них. Это разные редиректы. Это 500ые коды сделанные вручную. Это отсутствие прав доступа. Всё что по-любому закончится HTTPException или RedirectBack. Программа запуститься, но ошибка может быть вызвана тем, что во внешних условиях что-то идёт не так - нет прав доступа, или этот кусок программы сейчас отключен. То есть это не косяк кода, а сознательно установленный запрет. Эти ошибки чаще всего нужно переводить на другой язык или писать заглушку. Эти ошибки как правило бросаются фреймворком или приложением, и имеют либо неймспейс как у фреймворка, либо что-нибудь вроде \App\HttpException;

    В третью группу я отнёс ошибки, которые требуют внешних зависимостей. Насчет этой группы я пока не уверен, может быть это из-за того что я неправильно разобрался с первыми двумя. Предположим у нас есть модуль авторизации пользователя и есть модуль для работы с JWT-токенами. Вот когда модуль не смог разобрать JWT токен - он должен кинуть ошибку "я отработал и решил, что что-то пошло не так, но дальше - не моя забота". JWT разбор выполняет очень узкую задачу - парсинг токена. Туда не всунешь зависимостью модуль авторизации, это как поставить директора в подчинение работнику. Можно попробовать НЕ-бросать эту ошибку путем того, что инициировать проверку токена в модуле Авторизации, чтобы прямо там её и обработать. Но это странно, потому что Авторизация может быть сделана десятью путями и каждый из них зависимостью хардкодить - не очень хорошо. Именно эти ошибки должны иметь неймспейс, потому что их будут ловить и с ними работать, пытаясь их заглушить. То есть на уровне модуля - это критическая ошибка. А на уровне программы - это предупреждение.

    На текущий момент мне кажется это правильным подходом. Если найду что-то ещё исправлю.
    Ответ написан
    Комментировать
  • А можете поревьювить?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Глаза радуются, когда такой код видишь, не надо спрашивать - где он тот кто писал

    Немного косметики:
    1. Константы можно определять в интерфейсах, это здорово помогает, незачем для них целая папка с классами

    2. Билдер предполагает (на мой взгляд) строительство чего-то сложного в такой нотации
    ->where()->where()->group(). Если нечто просто возвращает другой объект, это может быть фабрикой. Я имею в виду даже называться фабрика. Билдер означает "здесь столько параметров, что их в одном месте тупо не проставить, и нужно отсюда взять один, отсюда другой, соединить хитро" и тд. поэтому он билдер.

    3. Есть там место где тебе очень нравится if ($a instanceof Class) и раз 20. Можешь закинуть имена классов в качестве ключей в массив и тупо чекать isset(). Разве что ты планируешь наследоваться, тогда isset() будет не очень. Но в любом случае форич упростит этот код строк на 30

    4. по эксепшенам как бы не превратилось в холивар, но смело бросай стандартные Пхпшные эксепшены с небольшой ремарочкой - оберни их в свой неймспейс (в этом случае категории останутся стандартные, а твой модуль будет бросать как бы "свои собственные"). Для случаев когда тебе очень нужно что-то логировать и вытягивать из эксепшена, я бы предусмотрел как и у тебя ClientException только вместо Response просто пхал бы туда ...$arguments. Что кинешь - то и достанешь потом. То есть стандартные мессаг, код и предыдущий будет как у всех эксепшенов - а аргументы - чтобы их логировать. Не думаю что очень ты выиграл от того, что сделал эксепшен в котором первым параметром обязательно респонс. Теперь он может быть использован только здесь и нигде больше. Если эксепшен приводит к каким-то действиям кроме "поймать", "перебросить", "уведомить" или "залогировать" - очень вероятно что это не эксепшен. Хотя такой вариант может быть почему нет.

    5. Интерфейсы лежат вместе с классами это не плохо, но рядом с интерфейсом нет такого же класса, а идут другие, реализующие интерфейс. Похоже на абстракцию, которая могла бы быть. ActionInterface.php, Action.php и папка Action где уже лежат Actions. Но это тоже косметика. В самих экшенах я бы все таки добавил слово Action несмотря на то что неймспейс тоже Action. Если открыть много файлов в редакторе, то сверху одинаковые имена могут дублиться, а так видно - что тут речь про экшен, а там не про экшен.

    6. Вот что мне показалось странным - у тебя куча "экшенов" подразумевающих что это "действие". Но там внутри лежат сущности названные "Действие". Ну то есть ты создал много классов задача которых входные аргументы проверить по типу (кинуть InvalidArgumentException если косяк, по сути), и больше ничего. Ну у них есть геттеры и свойства. Это состояние никак не меняется, оно просто устанавливается и валидируется. Можно. Выглядит красиво, аккуратно. Но бегает у меня сзади призрак который намекает что зарраза, столько файлов создал, он не задолбался? Впрочем если апишка бота непредсказуема - типа на одно возвращает одно, на второе другое и нет ничего общего - то такой способ валидации приемлем. К сожалению кроме разработчика который будет на базе этой штуки лепить, никто не сможет на них никак среагировать, т.к. InvalidArgumentException это в первую очередь "уведомить разработчика что сюда попало то, что не должно", отловить и перевести на несколько языков такую ошибку не получится. Собственно поэтому прибегают к валидации там, где этой штукой будет пользоваться менее опытный разработчик или пользователь.

    Наверное всё, можно пообщаться в той же телеге, если интересно детальнее. В целом понравилось
    Ответ написан
    2 комментария
  • Что нужно знать про ООП?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    А я бы добавил что ООП это украшение кода, а не его суть

    Cейчас есть способы платить Амазону и вообще не писать код, создавая апишки в админке с помощью мышки. Все что будет нужно от ПХП - это делать простые скрипты которые передают данные из точки А в точку Б. Там вообще не нужен будет ООП, потому что не будет понятия "цельный проект" в рамках папки с файлами. Цельный проект это будет куча компьютеров, а на этом конкретно есть передача из А в Б. И тут уже PHPшники посмеются)) Они то готовы к такому

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

    https://qna.habr.com/q/655113#answer_1431141

    думаю сейчас ты увидишь как набегут великие архитекторы, которые давали тебе советы по этим словам и начнут говорить что то не про это, а это не так и это не здесь. вот это еще одно что надо знать про ООП. Ты никогда не услышишь, что ты прав, потому что термины заменили им мозг, а если им сказать об этом - они объединяются в стаи, чтобы завалить тебя стикерами и унижениями.
    Ответ написан
    19 комментариев
  • Как обновить версию libxml в OpenServer?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    В опенсервере есть модулес пхп и там твой пхп который ты выбрал в панельке стартовой. Заменив там, обновится. А опенсервер каждый раз новый. Или ставить поверху без замены или помнить шо такой то модуль менять нельзя. Можно сделать умнее канеш но долго и никто не выиграет от этого
    Ответ написан
  • Не работает Ajax запрос при отправке формы обратной формы. В чем причина?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Может ты скрипт свой вешаешь на onSubmit еще до того как загрузилась jquery у которого async?
    Ответ написан
  • Как подсчитать только вложенные элементы массива без родительских?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Добро пожаловать в пхп. Ты нащупал одну из мощнейших его проблем, которую никакой авторитетный пхпшник никогда не признает.

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

    Сначала по существу, потом о вечном...

    Количество родительского - count($array);
    Когда ты поставил в count() вторым параметром единицу - ты посчитал сумму количеств во всех элементах. Потом отнял количество в главном массиве. Технически ты получил ответ, но сама задача - сначала сделать пачку-пачек а потом посчитать количество элементов во всех пачках без учета основной пачки - это немного странно

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

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

    Вот тебе функции из моей библиотеки:

    // is_array
      // проверяет массив на ключи - цифровые, идущие по порядку с 0
      function _is_array($array) : bool
      {
        if (! is_array($array)) return false;
        if (! $array) return true; // empty array is array too
    
        $i = count($array);
        while ($i-- && ! array_key_exists($i, $array)) return false;
    
        return true;
      }
    
      // is_list
      // проверяет является ли массив - списком (list) без буквенных ключей. цифровые ключи в отличие от array могут идти в любом порядке
      function _is_list($array) : bool
      {
        if (! is_array($array)) return false;
        if (! $array) return true; // empty list is list too
    
        // contains string key? not a list
        foreach (array_keys($array) as $key) {
          if (is_string($key)) return false;
        }
    
        return true;
      }
    
      // is_assoc
      // проверяет, является ли массив "грязным" - содержит хотя бы один строковый ключ
      function _is_assoc($array) : bool
      {
        if (! is_array($array)) return false;
        if (! $array) return false; // empty assoc is not an assoc
    
        // contains string key? there's assoc
        $result = false;
        foreach (array_keys($array) as $key) {
          if (! is_string($key)) continue;
    
          $result = true;
          break;
        }
    
        return $result;
      }
    
      // is_dict
      // проверяет, является ли массив - словарем (dict), без цифровых и пустых ключей
      function _is_dict($array) : bool
      {
        if (! is_array($array)) return false;
        if (! $array) return false; // empty dict is not a dict
    
        foreach (array_keys($array) as $key) {
          if (is_int($key)) return false; // 0,1,2
          if (! $key) return false; // null, ''
        }
    
        return true;
      }


    Теперь массив для тебя - это пачка чего-то.

    Лист, или список - это пачка которая прошла через фильтры (обычно функции фильтрации не изменяют ключей, а просто выбрасывают лишние), или это еще бывает пачка привязанная к таблице-связке в many-to-many.

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

    Dict - полноценный словарь, ключ-значение, являющийся единицей, которую надо класть в массив целиком и воспринимать как цельную сущность.

    Вместо Dict можно использовать new StdClass или другой обьект. В общем дикт это ленивый обьект. Впадлу писать класс и вообще тут одну задачку решить, не хочется - вот тебе дикт.
    Ответ написан
    Комментировать
  • Суть массивов в js?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Смотри, разделение на массивы и обьекты имеют очень конкретный смысл.

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

    А объект - это не пачка, это скорее именованный список, то есть по сути одна неделимая штука. Такая как строка. Или как цифра. Хреновина описывающая что-то. Возраст 30. Имя Василий Петрович Голобородько. Ты можешь к этим свойствам подойти как к пачке - только они разные по смыслу и типу данных.

    Пробежаться по имени а потом по возрасту применив к ним преобразование - это крышей уедешь разбирая все возможные "а если". А вот пробежаться по пачке юзеров взяв их имена или возрасты - это уже можно.

    Внутри в обьекте, в одном из именнованных свойств может быть пачка чего-то - это будет массив. Массив это пачка чего-то одинакового.
    Ответ написан
    Комментировать
  • Как сохранить в переменную объект с другим свойством не изменяя объект?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Рассматривай обьект как ящик с данными.
    Создал ящик. Положил туда что-то. На ящик навесил ярлык с переменной.
    Хочешь другой обьект - это другой ящик создавай новый или копируй (через клонирование) старый. Можешь в переменную положить другой ящик.

    Но помни что если ни одна из переменных не содержит информацию о твоем ящике, то ты его потерял.
    То есть
    $obj = new Obj;
    $obj = new Obj;

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

    Создавай вторую. И там играйся со вторым ящиком
    Ответ написан
    Комментировать
  • Где посмотреть\почитать нормальные уроки по ООП в PHP?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Если ты начнешь внимать "глубину ооп" то лет через 8 тупого и бесполезного долбалова и попыток уговорить хоть кого-нибудь тебе помочь понять суть и смысл, слушая тупые отговорки, что "ты все не так понял", "это всего лишь инструмент", "нужно найти суть", "это не всегда нужно", ты в конце концов придешь что ООП это всего лишь украшение обычных функций, когда проект не влазит на пластиковую доску с маркерами.

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

    Дальнейшее "понимание глубины" не несет под собой ничего кроме того что есть авторитет, и есть вот ты. и ты никогда не станешь авторитетом, потому что он гуру и на горе. А ты здесь. И не бывает так, чтобы ты и авторитет. Зато бывает менталитет. Извиняюсь, кого обидел
    Ответ написан
  • Как правильно реализовать реализовать классы Родитель->Потомок?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Вот как я понимал события

    <?php
    
    $events = [];
    
    $on = function (string $name, callable $func) use (&$events)
    {
      $events[ $name ][] = $func;
    };
    
    $fire = function (string $name, $emitter, ...$arguments) use (&$events)
    {
      if (! isset($events[ $name ])) return;
      
      foreach ($events[ $name ] as $func) {
        call_user_func($func, $name, $emitter, ...$arguments);
      }
    };
    
    // когда машина выйдет с завода - поехали!
    $on('car-created', function ($event, $car, ...$comments) { var_dump($car, $comments); });
    
    // ...some application code
    
    // пришло время, тачка готова.
    $fire('car-created', $car, 'faster', 'darling');


    Что тут есть. Есть массив, хранилище, где будут лежать инструкции $func "что сделать", привязанные на ключ $name - "когда сделать".

    Есть функция $on, которая тупо на некое имя записывает в хранилище что делать.
    Есть функция $fire, которая "стреляет" - начинает выполнять всё, что висит на этом `$name`. В параметре эмиттер может быть что угодно, что душе хочется - обычно это виновник торжества, из-за чего событие стрельнуло.

    В аргументс тоже передаешь чего хочешь, параметры массивы и так далее.

    Вот когда понимаешь что события, это вот так вот просто, сверху можешь на них навесить классы, чтобы понять что эвентс лучше хранить в классе "Диспетчер", а типы событий тоже могут быть классами вместо `$name`, тогда в них можно какие-то функции зашить внутрь.

    Пока просто вот так отнесись к этому
    Ответ написан
    Комментировать
  • PHP Почему не равны две строки?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    очень вероятно что одна строка написана в блокноте с выбранным UTF8-BOM, а вторая написана на сервере или на чьём-то ноутбуке где было выбрано Windows-1251, а потом просто скопировано или вставлено в базу как было

    ну и как ты сам нашел в комментах - __debugInfo магический метод может менять вывод var_dump.
    Ответ написан
    Комментировать
  • Как реализовать запрос с использованием PHP SoapClient?

    gzhegow
    @gzhegow
    aka "ОбнимиБизнесмена"
    Если запрос не HTTPS рекомендую установить программу WireShark, и попробовать посмотреть в каком виде идут другие запросы. Потом можно составить запрос в виде текста и отправить его. А уже потом прикидывать как на это все навесить код, который в пыхе вшит под словом Soap.

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