开发者

How do you create a function with code blocks that wrap around commonly used code?

开发者 https://www.devze.com 2023-04-11 05:20 出处:网络
I have a do...while loop and a try...catch block that wraps around database centric code. The do...while and try...catch serves the purpose of preventing transaction deadlocks, and it does so very wel

I have a do...while loop and a try...catch block that wraps around database centric code. The do...while and try...catch serves the purpose of preventing transaction deadlocks, and it does so very well from extensive testing. My problem now is code redundancy. I cannot figure out a way to deploy a function or method that performs the do...while and try...catch around a generic set of database centric code without using the "evil" eval command. I imagine this comes up under other software design pattern scenarios.

This illustrates how I imagine the method with 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);
    }
}

This illustrates an undesired coding practice if I were to use the method above:

// code

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

// code

I am looking for a solution that does not include the use of the eval command.

After writing all of this up, I just thought of the possibility of flanking my code with include statements:

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

But I am looking for something more OOPish and l开发者_运维百科ess hackish. I don't even know if the above would work and the includes may carry an unnecessary performance expense. So the issue still warrants inquiry and discussion for the best solution.


You could pass in an anonymous function:

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

Database::deadlockSafeTransaction($myFunction);

Call the function in your deadlockSafeTransaction code:

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

More information is available in the PHP docs. If you're using PHP < 5.3.x you can also use the call_user_func method.


Use callbacks:

 function doInTransaction($fn) {

     // stuff

     $fn();

     // more stuff

 }

and then

 doInTransaction(function() {

   // whatever

 });

As to the question how to pass the context into the function, I don't think using globals is a good idea. Much better is to pass what you need explicitly to the function:

function doInTransaction($fn) {

    // stuff

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

    // more stuff
}

and the function should be prepared to accept what's gets passed to it:

doInTransaction(function($connection, $logFile) {

    $x = $connection->xxxx

})

Even better option is to make function a Delegate and just give it the whole "parent" object:

function doInTransaction($delegate) {

    // stuff

    $delegate($this);

    // more stuff
}

doInTransaction(function($dbObject) {

    $dbObject->doSomething(...);

})


In C# you coulduse a lambda expression to do this in a type-safe way. Not sure if PHP has anything similar.

DeadlockSafeTransaction(() => DoSomething());


You can use an interface class to implement an OOP callback.

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

Your code would be something like:

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

class someClass implements databaseAction{
    //regular class stuff

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

Your Db class would then be this:

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号