Так получилось, что в последние несколько лет я сшиваю Франкенштейнов, а не ваяю милые фарфоровые статуэтки пастушек и трубочистов. Я создаю решения на базе Magento 2. Это значит, что исходный материал у меня — мечта любого археолога. Культурный слой со следами различных "эпох" и "цивилизаций". По нему можно изучать развитие программистской мысли в PHP/JS сообществах в течение последнего десятилетия.
И это только базис, а надстройка — сторонние модули, которые нужно интегрировать вовнутрь. Вот тут уже можно столкнуться с проявлениями внеземного разума. Некоторые модули созданы развитыми существами, очень похожими по мышлению на создателей базиса, но попадаются такие, что хочется приобнять автора за плечо, проникновенно заглянуть ему в глаза и по-дружески так спросить: "Ты с какой планеты, родной?"
Сшить Франкенштейна из такого материала помогает отладчик (debugger). Ниже идёт мой персональный топ приёмов кодирования, которые способны усложнить жизнь любому, кто, как и я, ежедневно использует отладчик в своей жизни. Он небольшой, на четыре позиции, но каждый раз, когда я сталкиваюсь с подобным при отладке — я печалюсь. Может быть мой пост уменьшит количество скорбей в мире, а может и нет. Я, по крайней мере, попытаюсь.
Обфускация и шифрование кода
Это вне конкурса. Я пару раз сталкивался с модулями, для работы которых нужен ionCube, и могу сказать, что последнее, что я сделаю — поставлю в свой проект подобный модуль. Я полностью поддерживаю минификацию JS-кода, особенно, когда рядом идёт обычный исходник, но обфускация и шифрование — дистиллированное, концентрированное зло. Это я вам как Интегратор говорю.
IV. Однострочный код
Экономия на строчках кода — самое безобидное в моем списке:
if ($cond) aaa(); else bbb();
Зависание на два шага на этой строке при пошаговом выполнении программы (вычисление условия, выполнение ветки true
или false
). Ничего страшного, нужно просто держать в голове, сколько раз ты выполнил step-over на этой строке, и отслеживать значение $cond
в списке переменных. Со временем нарабатывается автоматизм.
Чуть хуже то, что ты не можешь поставить безусловную точку останова (breakpoint) на ветке true
или false
. Придётся вместо одного клика в IDE поработать мышкой/клавиатурой чуть подольше, добавляя условную точку останова.
Идеальный вариант, когда каждый исполняемый шаг (условие, true
-ветка, false
-ветка) находится на своей строке:
if ($cond)
aaa();
else
bbb();
III. Результат-выражение
Использование выражений в условиях:
if (exp()) ...
циклах:
foreach (exp() as $item) ...
в качестве параметров:
foo(exp(), ...)
и возвращаемого результата:
return exp();
не только делает код "плотнее", облегчая его понимание, но и затрудняет отладку — ты просто не видишь значений выполнения выражений в списке переменных отладчика. Приходится добавлять watches (интересный вопрос, а если мониторить генераторы через watches, повлияет ли это на выполнение программы?).
Идеальный вариант — временная переменная:
$exp = exp();
if ($exp) ...
II. Множество точек выхода
Я множество раз сталкивался с рекомендацией иметь только одну точку выхода из функции и множество раз сталкивался с нарушением этой рекомендации (пример выдуманный, но типовой):
public function onEvent($event) {
if($event == 'entrance') {
return 'entranceRoute';
} else if($event == 'exit') {
return 'exitRoute';
}
return 'defaultRoute';
}
Вот более правильный вариант:
public function onEvent($event) {
$result = 'defaultRoute';
if($event == 'entrance') {
$result = 'entranceRoute';
} else if($event == 'exit') {
$result = 'exitRoute';
}
return $result;
}
Всё, мне не нужно разбрасывать точки останова на каждом return
или делать step-out с первой строки (если вызывающий код даёт мне возможность посмотреть результат в отдельной переменной), чтобы понять, чем закончилось выполнение. Представляете себе функцию на 120 строк и 22 return'а внутри? А я такую собственноручно дебажил и подозреваю, что это не предел.
I. Каскадный вызов методов
Мой фаворит — method cascading:
$collection
->addFilterByProduct(...)
->addShowInStoresFilter(...)
->addPublicFilter(...)
->addApprovedStatusFilter(...)
->addCreatedAtLessThanNowFilter(...);
Если мне нужно попасть внутрь метода addApprovedStatusFilter()
, который является интерфейсным и имплементирован в нескольких различных классах (конкретный класс определяется во время выполнения), то самое простое — поставить точку останова на $collection
и по-очереди проходить всё (addFilterByProduct
, addShowInStoresFilter
, addPublicFilter
) вплоть до нужного места. Если соединить это с использованием выражений в параметрах и возвращаемых результатах, то путь становится совсем не близкий. В оригинале данный код выглядит так:
$collection
->addFilterByProduct($this->getProduct())
->addShowInStoresFilter($this->_storeManager->getStore()->getId())
->addPublicFilter()
->addApprovedStatusFilter()
->addCreatedAtLessThanNowFilter();
Да, с каскадированием методов код становится более читаемым, но дебажить его становится сложнее. Ничего не имею против каскада set'еров (я, как правило, не дебажу сеттеры):
$answerModel
->setAuthorName(...)
->setStatus(...)
->setCreatedAt(...)
->setAuthorEmail(...)
->setCustomerId(...)
->setHelpfulness(...)
Но код, который содержит логику, который может быть придётся дебажить, а может быть даже самому, лучше писать "олдскульно" (я сам так и делаю):
$collection->addFilterByProduct(...);
$collection->addShowInStoresFilter(...);
$collection->addPublicFilter(...);
$collection->addApprovedStatusFilter(...);
$collection->addCreatedAtLessThanNowFilter(...);
Намного сложнее для восприятия стало?
Или вот рекомендации хорошего стиля программирования:
ladder.up().up().down().up().down().showStep();
Посмотрите на это с точки зрения интегратора, который должен залезть внутрь второго down
'а.
Резюме
Я не имею в виду, что данные приёмы используют в своём коде "инопланетяне". Вовсе нет, в большинстве своём они, наоборот, направлены на сокращение количества кода. Но данные приёмы осложняют отладку. Человек не обладает скоростью компьютера и, чтобы выйти на проблемный код, интегратор должен сначала просканировать (не понять, а именно просканировать) ход выполнения программы в ключевых точках. Всё вышеперечисленное, имея с одной стороны задачу улучшить понимание кода, по факту, во время отладки, этому самому пониманию мешают. Мешают не в месте расположения кода, а мешают добраться до проблемного участка, который, в общем, и нуждается в настоящем понимании.
Disclaimer
Изложенное выше является результатом персональной профессиональной деформации и может отличаться от мнений, основанных на других профессиональных деформациях.
Комментарии (43)
vlreshet
13.03.2019 12:09Идеальный вариант, когда каждый исполняемый шаг (условие, true-ветка, false-ветка) находится на своей строке:
if ($cond) aaa(); else bbb();
По-моему, идеальный вариант это когда каждая ветка условия имеет свой логический блок
if ($cond) { aaa(); } else { bbb(); }
transcengopher
13.03.2019 14:15Интеграторы против Builder Pattern?
Danil1404
13.03.2019 15:14Это же не builder, а method chain.
transcengopher
13.03.2019 15:21Согласен. Сработало искажение на базе моего опыта — я не припомню Builder'ов, которые не позволяли бы вызывать методы в цепочке, особенно те, что должны быть «одноразовые», потому я почти перестал различать эти два паттерна.
bm13kk
13.03.2019 20:48Я понимаю боль от дебага функций раннего выхода.
Но
1) метод на 120 строк — по определению боль
2) читаемость кода важнее удобности дебага. Единый ретурн ухудщает читаемость.
У тебя есть метод. в определенный моент он ветвится. Психологически легче быстро отработать короткий случай и забыть о нем.
3) как советовали выше — используйте другой дебаггер. Посмотрите прогресс ИДЕИ за последний год — там много фич как раз для дебага.
Да, у вас не получится однокликовое решение. Но работая с маджентой — вы себе сами предопределили условия
4) возможно наибыстрейшее решение — это банальное редактирование кода. Одна комбинация клавиш и код теперь дебажится. А потом все откатить через CVS.flancer Автор
13.03.2019 21:27Согласен со всем, кроме:
2) читаемость кода важнее удобности дебага. Единый ретурн ухудщает читаемость.
У тебя есть метод. в определенный моент он ветвится. Психологически легче быстро отработать короткий случай и забыть о нем.При чтении кода возврат в третей-пятой строке кода не отменяет необходимости читать метод до конца, чтобы его понять. Это при отладке можно выскочить на третей-пятой строке по return'у и не парится, что там далее (если условия так сработали), а для понимания всего метода нужно читать метод целиком. В таком случае
.... $result = 1234; ... return $result;
ненамного хуже для читабельности, чем
... return 1234; ...
если, разумеется, использовать для возврата переменную
$result
по-умолчанию. К тому же единая точка возврата дисциплинирует, заставляя надёжнее изолировать различные результаты черезif
-else
, что весьма пригождается при рефакторинге. Но это мне мой опыт так говорит, у вас он может быть другим.bm13kk
14.03.2019 00:01Мой опыт другой.
Смотрите. Если использовать переменную резалт — то возможно ее кто-то где-то как-то изменит. Если и правда изменит — значит это уже другой метод.
if ... $res = 'value'; .... $res += '-postfix'; .... return $res;
должно стать
private function calculate() { if ... return 'value'; ... return ...; } public function get() { return $this->calculate() + '-postfix'; }
Делая ранний ретурн — ты гарантируешь что логика метода только про это. Что артефектов с результатом потом не будет.
Именно для улучшения понимания лучше сокращать метод. В методе должна быть одна центральная логика. И не больше парочки ифоф для крайних случаев. В крайних случаях почти всегда можно завершать метод. И тогда чтение метода как раз улучшается. Сразу видна основная логика и маловероятные (и малонужные) побочки.
Единственный случай, когда единая точка выхода хороша — настоящая функциональщина. Но сюда не относится ни пхп ни маджента. Более того, функциональщина в корне меняет стиль написания. И почти всегда, иф — это будет отдельный метод или последний операнд.
[любоя практика] дисциплинирует
Ужастный подход к программированию и процессам. Дисчиплинировать должны анализаторы, компиляторы и прочие гейты в СИ. Такой подход, это как сказать «я не буду писать хорошо, чтобы читатель не расслаблялся и был готов самостоятельно найти ошибки».
flancer Автор
14.03.2019 07:38Делая ранний ретурн — ты гарантируешь что логика метода только про это.
Делать единственный возврат — вот это гарантия, что логика метода только про это. Ваш пример, переписанный для одной точки возврата:
if ($cond){ //... $res = 'value'; } else { //... } return $res;
Такой подход заставляет читать код метода до конца, а не до первого return'а, и понимать его во всей полноте, а не только "основную логику" (или "наиболее часто встречающуюся"? или "самую тривиальную"? — что там обычно первым возвратом ставят?).
я не буду писать хорошо
Что такое хорошо и что такое плохо — зависит от контекста. Никто не может написать код, который хорош во всех контекстах. Лично я пишу не для того, чтобы мой код легко читался, а для того, чтобы он проще модифицировался.
VolCh
14.03.2019 11:56Делать единственный возврат — вот это гарантия, что логика метода только про это.
Как раз не гарантия. Хорошо если визуально сразу видно две ветки, а что если их 10 и они не выделены как полноценные альтернативы? Типа
(if ($cond){ $res = 'value'; } if (!$cond) { // a lot of code $res='anotherValue'; } return $res;
flancer Автор
14.03.2019 12:18В таком случае ставьте return'ы — я буду дебажить с первой строки метода. Со временем ваш код может превратиться в подобие этого:
сэволюционировавший кодpublic function isApplicable() { $p = $this->getProduct(); if (!$p) { return false; } // has image for the current mode if (!$this->getValue('img')) return false; $now = Mage::getModel('core/date')->date(); if ($this->getDateRangeEnabled() && ($now < $this->getFromDate() || $now > $this->getToDate())) { return false; } // individula products logic $inArray = in_array($p->getSku(), explode(',', $this->getIncludeSku())); if (!$p->getSku()) $inArray = false; // include skus if (0 == $this->getIncludeType() && $inArray) return true; // exclude skus if (1 == $this->getIncludeType() && $inArray) return false; // use for skus only if (2 == $this->getIncludeType()) return $inArray; if ($this->getPriceRangeEnabled()) { switch ($this->getByPrice()) { case '0': // Base Price $price = $p->getPrice(); break; case '1': // Special Price $price = $p->getSpecialPrice(); // or $this->_info['special_price'] break; case '2': // Final Price $price = Mage::helper('tax')->getPrice($p, $p->getFinalPrice()); break; case '3': // Final Price Incl Tax $price = Mage::helper('tax')->getPrice($p, $p->getFinalPrice(), true); break; case '4': // Starting from Price $price = $this->_getMinimalPrice($p); break; case '5': // Starting to Price $price = $this->_getMaximalPrice($p); break; } if ($p->getTypeId() == 'bundle'){ $priceMin = $p->getMinPrice(); $priceMax = $p->getMaxPrice(); if ($priceMin < $this->getFromPrice() && $priceMax > $this->getToPrice()) { return false; } } else if ($price < $this->getFromPrice() || $price > $this->getToPrice()) { return false; } } $attrCode = $this->getAttrCode(); if ($attrCode) { if (!array_key_exists($attrCode, $p->getData())) { // has attribute condition return false; } // compatibility with the `Amasty: Custom Stock Status` extension // if the `Use Quantity Ranges Based Stock Status` property setted to `Yes` // so the value of the `Custom Stock Status` is dynamic // and setted to the product value is not used if (('custom_stock_status' === $attrCode) && (Mage::helper('core')->isModuleEnabled('Amasty_Stockstatus'))) { if ($this->getAttrValue() != Mage::helper('amstockstatus')->getCustomStockStatusId($p)) { return false; } } elseif ($this->getAttrValue()) { $v = $p->getData($attrCode); if (preg_match('/^[0-9,]+$/', $v)){ if (!in_array($this->getAttrValue(), explode(',', $v))){ return false; } } elseif ($v != $this->getAttrValue()){ return false; } } elseif (!$p->getData($attrCode)) { // sometimes needed for has attribute condition too return false; } } $catIds = $this->getCategory(); if ($catIds) { $ids = $p->getCategoryIds(); if (!is_array($ids)) return false; $found = false; foreach (explode(',', $catIds) as $catId) { if (in_array($catId, $ids)) $found = true; } if (!$found) return false; } $stockStatus = $this->getStockStatus(); if ($stockStatus){ $inStock = $p->getStockItem()->getIsInStock() ? 2 : 1; if ($inStock != $stockStatus) return false; } if ($this->getIsNew()){ $isNew = $this->_isNew($p) ? 2 : 1; if ($this->getIsNew() != $isNew) return false; } if ($this->getIsSale()){ $isSale = $this->_isSale() ? 2 : 1; if ($this->getIsSale() != $isSale) return false; } if ($this->getCustomerGroupEnabled() && ('' === $this->getCustomerGroups() || // need this condition, because in_array returns true for NOT LOGGED IN customers (!in_array(Mage::getSingleton('customer/session')->getCustomerGroupId(), explode(',', $this->getCustomerGroups()))))) return false; // finally ... return true; }
VolCh
14.03.2019 12:45Любой код может превратиться в такой. Сделаете c одной точкой возврата, а вам добавят промежуточных. Причём он станет ещё сложнее для понимания и изменения, чем изначально с ранними возвратами, потому что два подхода будет смешано.
flancer Автор
14.03.2019 12:51Правильно, потому что чья-то "религия" позволяет ставить return'ы где ни попадя, а чья-то нет. В результате имеем микс. С одной точкой возврата получится такая вложенность по if'ам, что придётся разбивать проверку на связные части. Придётся делать код, более устойчивый к модификациям, т.к. придётся глубже нырять в предметную область и лучше понимать её. Поставить ещё один return гораздо проще.
VolCh
14.03.2019 14:01А у кого-то есть компромиссы типа ранние возвраты только до основной логики. И никаких «придётся» нет, если никто или ничто не следит за вложенностью и т. п.
RSM
14.03.2019 01:48Не используй код код который недостаточно документирован или который ты не можешь понять прочитав (ну или на крайний случай натравив автоформаттер и прочитать). Тут два два варианта: или код очень плох или ты слишком туп что бы понять его. Оба варианта не годятся — или ты добавишь ложку говна в бочку меда или наоборот — ни первое, ни второе не принесут пользы. Дебаггер исправить ситуацию не поможет :)
flancer Автор
14.03.2019 07:07Не используй код код который...
Отличный совет! Жаль, что интеграторы не могут им воспользоваться.
Bluz
14.03.2019 09:56+1Ой, про единую точку возврата уже накидали, но хочется ещё подискутировать не эту тему.
Читать вот это
function foo(baz) { if (baz < 0) { return 0; } // ... // do any for result return result; }
Много проще чем это,
function foo(baz) { if (baz < 0) { result = 0; } else { // ... // do any for result } return result; }
особенно если проверок может быть много
function foo(baz) { if (baz < 0) { result = 0; } else if(baz > 100 && baz <= 1000) { result = do_f1(); } else if (baz > 1000 && baz <= 10000) { result = do_f2(); } else if (baz > 10000 && baz <= 100000) { result = do_f3(); } else{ result = do_f4(); } return result; }
Эта гирлянда вообще вызывает ассоциации с ктулху.
А уж если как-то так получается, что иерархия if/else'ов уходит вглубь на пару уровней, то совсем тушите свет, потому что третьему уровню контекст теряется: кто и зачем туда попал?flancer Автор
14.03.2019 10:08-1Если вы пишите код для того, чтобы его читать, то да — так удобнее. Особенно, если для вас замена
$result
наreturn
превращает ктулху-гирлянду в true-code-гирлянду:
function foo($baz) { if ($baz < 0) { return 0; } else if ($baz > 100 && $baz <= 1000) { return do_f1(); } else if ($baz > 1000 && $baz <= 10000) { return do_f2(); } else if ($baz > 10000 && $baz <= 100000) { return do_f3(); } else { return do_f4(); } }
Лично у меня
return
из начала-середины метода вызывает ассоциации только сgoto
.vlreshet
14.03.2019 10:46+1Если вы пишите код для того, чтобы его читать
Именно!!! Именно для этого я пишу свой код! Машине пофиг какой код исполнять, а мой код буду читать я, и мои коллеги. Читаемость кода — наше всё!flancer Автор
14.03.2019 10:53-1А я пишу код для того, чтобы его изменять. Изменять код буду я сам и мои коллеги. Изменяемость написанного кода — вот это "наше всё!" Я читал в детстве некоторые образчики perl-кода — ничего не понятно, но красиво-о-о. Занимательное чтиво.
VolCh
14.03.2019 12:26Думаю, всё-таки, перед изменениями вы код читаете :) И, вполне вероятно, читаете чаще чем изменяете.
flancer Автор
14.03.2019 12:46Вы правы, читаю я чаще, чем изменяю. Но читаю я именно для того, чтобы понять, где и что мне нужно изменить (или что здесь ничего менять не нужно). Код разбивается на классы/процедуры/функции не потому, что человек не может прочесть 2К строк подряд ("Войну и Мир" многие осилили). А для того, чтобы ограничить влияние изменений, особенно неправильных. Так что говорить, что мы пишем код для того, чтобы его читать — в корне не верно. Мы читаем, чтобы понимать. А понимаем, чтобы изменять. В противном случае было бы достаточно один раз написать код и один раз тесты к нему. Поэтому код должен быть не легко читаем, а легко изменяем. Кстати, удобнее читать код, который написан в одном файле, чем скакать от файла к файлу и обратно.
VolCh
14.03.2019 14:14Под чтением я, естественно, имею в виду чтение с пониманием, а не то как я латынь читаю :)
Спорное, очень спорное удобство. Даже не касаясь того, как средства разработки справляются с парсингом огромных файлов.flancer Автор
14.03.2019 14:18А для чего вам понимание кода?
VolCh
14.03.2019 14:29Самое частое, наверное — найти правильное место для изменений. Трудоемкость самих изменений — дело десятое.
flancer Автор
14.03.2019 16:03Кстати, в тему свежая публикация. Там тоже задумались, а что такое читабельность кода и для чего она:
Если код легко править — он читабельный? А вот это, пожалуй, верное направление мысли. Меняются требования, добавляются функции, возникают ошибки — и в какой-то момент кому-то приходится править ваш код. А чтобы при этом не породить новые проблемы, разработчику нужно понимать, что конкретно он редактирует и как правки изменят поведение кода. Итак, мы нашли новое эвристическое правило: читабельный код должен легко редактироваться.
VolCh
14.03.2019 16:13Выглядит как подмена понятий. Код может легко читаться, но сложно правиться. Ну, например,
if($cond) return true;
читается легче, чем
if ($cond) { return true; }
но правится сложнее.
flancer Автор
14.03.2019 16:26Согласен, несколько неточно. Нужно говорить о модифицируемости кода, а не о читабельности.
vlreshet
14.03.2019 14:23Код разбивается на классы/процедуры/функции не потому, что человек не может прочесть 2К строк подряд
Как раз таки именно потому! Прочитать код на 2к строк человек может, а вот держать в голове — ну, наверное, иногда это реально, но чаще всего — нет.
код должен быть не легко читаем, а легко изменяем
От этого выражения веет ламповым 2010-ым, где сайты представляли собой свалку файлов .php в корневой директории. Там было крайне легко что-то менять, и крайне сложно понять что, чёрт побери, происходит в целом.
Кстати, удобнее читать код, который написан в одном файле, чем скакать от файла к файлу и обратно.
Если использовать нормальный редактор кода, а ещё лучше IDE — то нет, ничем не удобнее. Даже наоборот.
У меня к вам такой неловкий вопрос… Вы занимались профессиональной разработкой с использованием фреймворков вроде Laravel, Symfony, Phalcon, Zend, или весь ваш опыт основывается на работе с продуктами вроде Magento?
flancer Автор
14.03.2019 15:09Код разбивается на классы/процедуры/функции не потому, что человек не может прочесть 2К строк подряд
Как раз таки именно потому! Прочитать код на 2к строк человек может
не находите противоречия?
где сайты представляли собой свалку файлов .php в корневой директории.
это ваше неверное представление о "ламповых" 2010-х, как неверно и ваше представление о том, что в свалке "легко менять" (возьмите на себя поддержку такой свалки хотя бы на пару лет).
У меня к вам такой неловкий вопрос…
У меня в профиле написаны языки, с которыми я имел дело. Magento использует Zend и Symfony для CLI. За Phalcon на могу ничего сказать — вообще не трогал. Laravel смотрел, но не более. Есть ещё неловкие вопросы?
vlreshet
14.03.2019 16:48Код разбивается на классы/процедуры/функции не потому, что человек не может прочесть 2К строк подряд
Нет, потому что вы вырвали цитату из контекста. Прочитать 2к — человек может, а держать в голове и помнить контекст — нет. А код это не книга, которая просто бегло читается.
Как раз таки именно потому! Прочитать код на 2к строк человек может
не находите противоречия?
это ваше неверное представление о «ламповых» 2010-х, как неверно и ваше представление о том, что в свалке «легко менять» (возьмите на себя поддержку такой свалки хотя бы на пару лет).
Эээх, пятый год такую свалку поддерживаю… Причём свалку энтерпрайз уровня, не сайт-визитку. Поэтому я знаю о чём говорю. Подкинуть лишний «if» в помойку — почти всегда легче, чем современный подход (создания модели, экшна в контроллере, проведения роутинга, написания тестов). Но лучше ли?
VolCh
14.03.2019 12:25> Лично у меня return из начала-середины метода вызывает ассоциации только с goto.
Именно! И альтернатива ранним возвратам как раз goto для меня. Но вот ваш пример для иллюстрации ранних возвратов не очень подходит — у вас все ветви равнозначные, кроме разве что первой. Ранний возврат или goto на возврат хорошо подходит когда есть несколько основных равнозначных ветвей и есть ветви для граничных случаев (в вашем пример, наверное, только отрицательные значения на неё подходят немного).
Bluz
14.03.2019 12:43Это потому что вы неправильно всё исправили =))
function foo($baz) { if ($baz < 0) { return 0; } if ($baz > 100 && $baz <= 1000) { return do_f1(); } if ($baz > 1000 && $baz <= 10000) { return do_f2(); } if ($baz > 10000 && $baz <= 100000) { return do_f3(); } return do_f4(); }
Вот так мне нравится большеflancer Автор
14.03.2019 12:47Я всего лишь переработал ваш код с $result'ами. Вы могли и его сделать чуть более красивым ;)
aikixd
14.03.2019 15:50-1Весь код в этой ветке плох. Все эти ifы должны лежать на рантайме языка. Объектах, функциях или еще на чем. Тогда и дебажить нечего будет.
megasuperlexa
14.03.2019 11:48Чуть хуже то, что ты не можешь поставить безусловную точку останова (breakpoint) на ветке true или false. Придётся вместо одного клика в IDE поработать мышкой/клавиатурой чуть подольше, добавляя условную точку останова.
Это что за IDE? в нормальных становишься курсором куда надо, жмёшь F9 и
вуаля
VolCh
Должно быть
для полной (почти) эквивалентности :)
А в целом, "более правильный" нужно заменить "более удобный для отладки отладчиком". :)
P.S. Я сторонник раннего выхода из функции/метода при валидации параметров и других подобных проверок. А для ситуаций типа onEvent() — вообще массиві или другие map структуры предпочитаю использовать типа
$result = self::eventResultMap[$map] ?? 'defaultResult'
P.P.S. А тернарки как, не доставляют?
flancer Автор
Согласен.
Доставляет всё, где нужно хоть чуть-чуть думать своим мозгом при трассировке. Я предпочитаю видеть результат выполнения программы глазами, а не мозгом :)