Magento 2 - хорошая практика использовать / избегать магических добытчиков?

21

Сборщики магии на Varien_Object(M1) и DataObject(M2) являются обычной практикой, но с Magento 2 кажется неправильным использовать его.

Хорошо:

  • легко читать / писать

Плохо

Вопрос

С Magento 2 у нас есть два новых метода:

  • getDataByKey($key)
  • getDataByPath($path)

Есть ли веская причина, чтобы все еще использовать getData($key)или какие-нибудь магические добытчики?


Редактировать:

@ Винай спасибо. Я не упомянул @methodметод, потому что мой подход был совсем другим.

Это только помогает IDE, но не влияет на другие вещи.

Существует несколько PR mergedf, которые являются «микрооптимизациями», такими как приведение (int)вместо intval()или получение размера массива вне циклов (даже для небольших массивов).

С другой стороны, есть

  1. магические добытчики, у которых есть некоторые "накладные расходы", как описал Мариус ....

    strtolower(trim(preg_replace('/([A-Z]|[0-9]+)/', "_$1", $name), '_'));
  2. getData($key) Методы также должны пройти 2-3 дополнительных проверки ...

    • if ('' === $key) {
    • if (strpos($key, '/')) {
    • if ($index !== null) {

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

$value = $observer->getVar_1();
$value = $observer->getData('var_1');
$value = $observer->getDataByKey('var_1');

Использование 3-го с /** @var some $value */мне кажется лучшим. (?)

sv3n
источник
1
Вы можете добавить методы в блок doc класса, чтобы инструменты анализа кода не жаловались на несуществующие методы. Также я думаю, что использование цифр в ключах само по себе является плохой практикой, поэтому здесь не должно быть указано «Плохо».
Лили Бергонзат

Ответы:

20

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

У getData*всех методов есть недостаток в том, что они должны быть аннотированы для вывода типа для работы.
Обычно это делается с помощью /* @var string $foo */аннотации над getData*звонком.
Это немного вонючий, потому что тип данных должен быть объявлен в классе, который содержит данные, а не в классе, который вызывает getData*.
Причиной этого является то, что если данные изменяются, класс, скорее всего, будет обновляться не всеми getData*сайтами вызовов.
Вот почему я думаю, что реальные методы повышают удобство обслуживания по сравнению с использованием методов getData*доступа.

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

К счастью, в настоящее время IDE действительно хороши в создании для нас реализаций getter и setter, так что этот аргумент больше не применяется.

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

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

Pros

  • @methodАннотации немного меньше коды записи по сравнению с реализацией реального получения и установки. Это едва ли верно в настоящее время, потому что IDE хороши в создании методов доступа, так что это больше не является реальным преимуществом.

Cons

  • Для вещей легко пойти не так, как надо.
    • Аннотации - это комментарии, они легко устаревают, когда код эволюционирует, но аннотации не обновляются. Реальные методы более надежны.
    • Можно добавить несколько аннотаций с разными сигнатурами типов без ошибки интерпретатора - поведение статического анализа кода не определено и может привести к незначительным ошибкам, которые трудно отследить.
    • Если существуют и @methodаннотация, и реальный метод с одинаковыми именами, сигнатура типа аннотации переопределяет реальный метод во время статического анализа кода, что противоположно тому, что делает интерпретатор PHP. Это снова может легко привести к тонким ошибкам.

По указанным выше причинам я лично не использую @methodаннотации, если могу их избежать.
Для кода, который предназначен для жизни долго, я реализую реальные методы получения и установки. Повышение удобства обслуживания стоит усилий по запуску среды IDE для их генерации.

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

Vinai
источник
Хорошее резюме. Спасибо, Винай. Это отвечает больше, чем я на самом деле спросил.
sv3n
1

У getData*всех методов есть недостаток в том, что они должны быть аннотированы для вывода типа для работы.

Обычно это делается с помощью /*@var string $foo */аннотации над getData*звонком. Это немного вонючий, потому что тип данных должен быть объявлен в классе, который содержит данные, а не в классе, который вызывает getData *.

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

Да, это вонючий, но можно (и нужно?) Избежать. Я думаю, что это очень распространенный код и часто предлагается:

/** @var Foo $product */
$product = $model->getProduct()
if ($product->getId()) {
    $product->doSomething();
}

Проблема в том, что вы просто предполагаете, что возвращаемое значение имеет тип Fooс вызываемым getId()методом.

Для удобства обслуживания почему бы не принять тип переменной и добавить InvalidArgumentException?

$product = $model->getProduct()
if ($product instanceof Foo && $product->getId()) {
    $product->doSomething();
}

Это также исправляет статический анализ кода в случае, если он $model->getProduct()имеет разные типы возврата - например Foo|false. В первом случае он будет жаловаться на звонки doSomething()по возможности false.

sv3n
источник