Как вы создаете функцию с блоками кода, которые оборачиваются вокруг часто используемого кода? - PullRequest
1 голос
/ 04 октября 2011

У меня есть цикл do ... while и блок try ... catch, который охватывает код, ориентированный на базу данных. Функция do ... while и try ... catch предназначена для предотвращения взаимных блокировок транзакций и очень хорошо справляется с обширным тестированием. Моя проблема сейчас заключается в избыточности кода. Я не могу найти способ развернуть функцию или метод, который выполняет do ... while и try ... перехватывает общий набор кода, ориентированного на базу данных, без использования «злой» команды eval. Я предполагаю, что это подходит для других сценариев проектирования программного обеспечения.

Это иллюстрирует, как я представляю метод с eval:

class Database {
    public static function deadlockSafeTransaction($code) {
        do {
            // setup a condition
            try {
                // start transaction

                eval($code); //evil

                // commit transaction
            }
            catch(Exception $ex) {
                // rollback transaction
                // analyze exception for deadlock and adjust condition or rethrow exception
            }
        } while(condition);
    }
}

Это иллюстрирует нежелательную практику кодирования, если бы я использовал описанный выше метод:

// code

Database::deadlockSafeTransaction("
// code - sometimes a lot of complicated code with other method calls and loops
");

// code

Я ищу решение, которое не включает использование команды eval.

После написания всего этого, я просто подумал о возможности фланкирования моего кода с помощью операторов включения:

include "do-try.php";
// database code
include "catch-while.php";

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

Ответы [ 4 ]

4 голосов
/ 04 октября 2011

Вы можете передать анонимную функцию:

$myFunction = function() {
  // do something
};

Database::deadlockSafeTransaction($myFunction);

Вызовите функцию в вашем коде deadlockSafeTransaction:

public static function deadlockSafeTransaction($myFunction) {
    ...
    $return = $myFunction();
    ...
}

Более подробная информация доступна в документации PHP . Если вы используете PHP <5.3.x, вы также можете использовать метод <a href="http://php.net/manual/en/function.call-user-func.php" rel="nofollow">call_user_func.

1 голос
/ 04 октября 2011

Используйте обратные вызовы:

 function doInTransaction($fn) {

     // stuff

     $fn();

     // more stuff

 }

, а затем

 doInTransaction(function() {

   // whatever

 });

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

function doInTransaction($fn) {

    // stuff

    $fn($this->databaseConnection, $this->logFile);

    // more stuff
}

, и функция должна быть готова принять то, что ей передано:

doInTransaction(function($connection, $logFile) {

    $x = $connection->xxxx

})

Еще лучший вариант -сделать функцию делегировать и просто передать ей весь «родительский» объект:

function doInTransaction($delegate) {

    // stuff

    $delegate($this);

    // more stuff
}

doInTransaction(function($dbObject) {

    $dbObject->doSomething(...);

})
0 голосов
/ 04 октября 2011

Вы можете использовать интерфейсный класс для реализации обратного вызова OOP.

http://php.net/manual/en/language.oop5.interfaces.php

Ваш код будет выглядеть примерно так:

interface databaseAction(){
    public function DbActions();
}

class someClass implements databaseAction{
    //regular class stuff

    public function DbActions(){
        //your code to be executed
    }
}

Ваш класс Db будеттогда будь таким:

class Database {
    public static function deadlockSafeTransaction($obj) {
        do {
            // setup a condition
            try {
                // start transaction

                $obj->DbActions(); //not evil

                // commit transaction
            }
            catch(Exception $ex) {
                // rollback transaction
                // analyze exception for deadlock and adjust condition or rethrow exception
            }
        } while(condition);
    }
}
0 голосов
/ 04 октября 2011

В C # вы можете использовать лямбда-выражение, чтобы сделать это безопасным для типов способом. Не уверен, что в PHP есть что-то похожее.

DeadlockSafeTransaction(() => DoSomething());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...