ncrocfer
ncrocfer

Reputation: 2570

perform several actions in php

According to you, what is the best solution in PHP to ensure the course of several php functions ? For example function A must return True to initiate the B function, and the B function must return True to initiate another function...

Is there a system like Rollback / Commit in SQL to ensure that in PHP please ?

Thank you.

Upvotes: 4

Views: 142

Answers (5)

Alix Axel
Alix Axel

Reputation: 154563

You can have a definition array:

$callbacks = array
(
    array
    (
        'function' => 'function_1',
        'rollback' => 'function_r1',
        'arguments' => array(1),
    ),

    array
    (
        'function' => 'function_2',
        'rollback' => 'function_r2',
        'arguments' => array(1, 2),
    ),

    array
    (
        'function' => 'function_3',
        'rollback' => 'function_r3',
        'arguments' => array(1, 2, 3),
    ),
);

And do something like this:

$callbacks = array_values($callbacks);

foreach ($callbacks as $key => $callback)
{
    if (call_user_func_array($callback['function'], $callback['arguments']) !== true)
    {
        // failed, calling necessary rollbacks in reverse order

        foreach (array_reverse(array_slice($callbacks, 0, $key)) as $rollback)
        {
            if (is_callable($rollback['rollback']) === true)
            {
                call_user_func_array($rollback['rollback'], $rollback['arguments']);
            }
        }

        break;
    }

    // success
}

Upvotes: 0

Blizz
Blizz

Reputation: 8408

If you have that many things to run through then it is best that you use a state machine.

In its simplest for this is just a loop while a "state" variable does not have the state "done". Every time one of the functions reports it is done, you just move up to the next state.

Simple example:

$nState = 0;
while ($nState != 3)
{
   switch ($nState)
   {
      case 0 : if (function1()) $nState = 1; break;
      case 1 : if (function2()) $nState = 2; break;
      case 2 : if (function3()) $nState = 3; break;
   }
}

Added advantage is that you can also go back. Obviously for clarity you can make the states constants and so on.

The state machine has the advantage that it keeps things neat and clear, even with a lot of functions.

I'm assuming here that the functions don't necessarily succeed on their first try and that sometimes you have to run them multiple times. If that is not the case, Stegeman's answer is the easier one.

Upvotes: 0

Rene Terstegen
Rene Terstegen

Reputation: 8046

Doing a chain of functions would look something like this:

try {
    if(!functionA()) {
        throw new Exception("Error message here", 100); // 100 can be any code, as long as it's unique to the other throw exception codes
    }

    if(!functionB()) {
        throw new Exception("Error message here", 101);
    }

    if(!functionC()) {
        throw new Exception("Error message here", 102);
    }
} catch(Exception $e) { 
    /**
     * Do some actions depending on the error code of the exception (100, 101, 102)
     */
}

But if I understand correctly you want to perform a serie of operations and only if they are all successful you want them to be final, otherwise you want to undo all the operations?

In this case it is hard to tell how you should implement this, cause you don't tell what you want to achieve.

But I can give you some advise. Most operations that are not reversable do have many possible checks. For example, if you want to be sure a file will be deleted from the filesystem you can first check if the file is writable (is_writable) and even exists (file_exists). If you first do all the checks of all operations and afterwards execute the operations, you can be pretty sure they will be executed successfully. Ofcourse it's possible you forget checks, or some things can't be checked, but I don't see an other option to fix this.

Upvotes: 2

Rodolphe
Rodolphe

Reputation: 497

There's no "rollback" available with php.

However if you work with exceptions, you can try your code, and as soon as you get an exception, call a rollback function in the catch section.

Pseudo code :

try {
  your_function_1(); // must throw exceptions on error
  your_function_2(); // must throw exceptions on error
} catch(Exception $e){
  your_rollback_code();
}

Upvotes: 2

binaryLV
binaryLV

Reputation: 9122

About "initiating functions", based on result of other functions - depends on context of functions. Few options:

if ( A() ) {
    if ( B() ) {
        anotherFunction();
    }
}

or

if ( A() && B() && anotherFunction() ) {
}

or

if ( A() && B() ) {
    anotherFunction();
}

In most cases, I would do the last one (if ( a and b ) { do c }).

Upvotes: 1

Related Questions