Intereting Posts

php 5.3 избегать дублирования try / catch, вложенного в цикл foreach (сэндвич кода)

У меня есть класс с методом А, который имеет существующую структуру следующим образом

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 } }