У меня есть класс с методом А, который имеет существующую структуру следующим образом
function methodA() { $providers = $this->getFirstSetOfProviders(); foreach ($providers as $provider) { try { $this->method1($provider); } catch ( Exception $e ) { // exception handling } } $providers = $this->getSecondSetOfProviders(); foreach ($providers as $provider) { try { $this->method2($provider); } catch ( Exception $e ) { // exception handling } } }
Контент для предложений catch идентичен. Есть ли способ организовать код, чтобы избежать повторения структуры try / catch, вложенной в цикл foreach? Концептуально, я пытаюсь сделать
function methodA() { foreach ($providers as $provider) { $method1 = function($provider) { $this->method1($provider); } $this->withTryCatch($method1); } ... } function withTryCatch($method) { try { $method; // invoke this method somehow } catch (Exception $e) { // exception handling } }
Это похоже на сэндвич кода , но я не уверен, как действовать в php.
UPDATE: try / catch вложен внутри цикла foreach, так что, когда генерируется исключение, оно обрабатывается, и выполнение продолжается до следующей итерации в цикле, а не для завершения цикла.
Хорошая вещь об Исключениях состоит в том, что они – объекты, которые могут быть переданы, как и любые другие. Таким образом, вы можете удалить дубликат кода (кроме основного шаблона) без значительного изменения:
foreach ($providers as $provider) { try { $this->method1($provider); } catch ( Exception $e ) { $this->handleException($e); } }
Примечание. Если вам нужен какой-то контекст в обработке исключений (например, $provider
), просто дайте handleException()
больше параметров.
Часть 2: Рефакторинг всего метода
Вы хотели бы знать, как дальше удалять дублирование. Я не знаю, имеет ли это смысл в вашем фактическом коде, это также может быть чрезмерным. Вам придется решить это самостоятельно. Ниже приведена реализация шаблона метода шаблона. Простите сырое имя, но я попытался следовать вашему примеру, и я понятия не имею, что вы делаете.
abstract class ClassThatDoesThingsWithProviders { public function methodA($providers) { foreach($provicers as $provider) { try { $this->methodThatActuallyDoesSomethingWithProvider($provider); } catch(Exception $e) { $this->handleException($e); } } } protected function handleException(Exception $e) { // handle exception } abstract protected function methodThatActuallyDoesSomethingWithProvider($provider); } class ClassThatDoesThing1WithProviders extends ClassThatDoesThingsWithProviders { protected function methodThatActuallyDoesSomethingWithProvider($provider) { // this is your method1() } } class ClassThatDoesThing2WithProviders extends ClassThatDoesThingsWithProviders { protected function methodThatActuallyDoesSomethingWithProvider($provider) { // this is your method2() } } class YourOriginalClass { protected $thingsdoer1; protected $thingsdoer2; public function __construct() { $this->thingsdoer1 = new ClassThatDoesThing1WithProviders; $this->thingsdoer2 = new ClassThatDoesThing2WithProviders; } public function methodA() { $this->thingsdoer1->methodA($this->getFirstSetOfProviders()); $this->thingsdoer2->methodA($this->getSecondSetOfProviders()); } }
Вы можете легко создать массив из thingsdoer1
и thingsdoer2
и, возможно, абстрактных getFirstSetOfProviders
и getSecondSetOfProviders
вместе. Также я не знаю, от чего зависят фактические реализации метода1 и method2, возможно, вы не сможете их извлечь, не нарушая сплоченности.
Но поскольку я не знаю вашего реального кода и что вы делаете, я не могу рекомендовать конкретную стратегию, рассмотрите мой пример выше как отправную точку.
function methodA() { try { $providers = $this->getFirstSetOfProviders(); foreach ($providers as $provider) { $this->method1($provider); } $providers = $this->getSecondSetOfProviders(); foreach ($providers as $provider) { $this->method2($provider); } } catch ( Exception $e ) { // exception handling } }