Avatar

I've got this pattern all over my code, to ensure that transaction are running correctly (esp. since they are nested). In PHP 5.3 I could extract the small payload ($value->update) into a neat little anonymous function and I'm done. But it has to be compatible PHP 5.1. Any ideas, how to not repeat this code over and over again *without* using create_function?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

class MyClass {
   public function doSomething() {
   	$sql  = SQL::getInstance();
		$mode = $sql->setErrorMode(SQL::THROW_EXCEPTION);
		
		try {
			$sql->startTransaction($useTransaction);
		
			foreach ($values as $value) {
				$value->update(false);
			}
		
			$sql->doCommit($useTransaction);
			$sql->setErrorMode($mode);
		}
		catch (Exception $e) {
			$sql->cleanEndTransaction($useTransaction, $mode, $e, 'MyException');
			return null;
		}
	}
}

Refactorings

No refactoring yet !

Bd69fe47540b08d8f3d92e68058d2a81

Michał Pochwała

July 29, 2010, July 29, 2010 10:58, permalink

No rating. Login to rate!

I hope it will help you.

A little comment to the naming convention for the methods. To have a method with transaction support use tx prefix for method name, eg:
* txDoSomething()
* txDoSomethingElse()

interface only for marking the transactional behaviour

1
interface Transactional{}

class which needs access to transactions (some kind of aspect)

1
2
3
4
5
6
7
8
9
10
11
12
13
class MyClass implements Transactional{
	private function __construct(){}
	public function noTransactionMethod($testParam1, $testParam2){
		echo "the noTransactionMethod invoked with params ".$testParam1. ' and '.$testParam2;
	}
	public function txWithTransactionMethod($testParam1, $testParam2){
		echo " the txWithTransactionMethod invoked with params ".$testParam1. ' and '.$testParam2.' ';
	}
	public static function createInstance(){
		$myClassObject = new MyClass();
		return new TransactionalProxy($myClassObject);
	}
}

proxy which add transactional 'aspect'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class TransactionalProxy{
	private $service;
	public function __construct(Transactional $service){
		$this->service = $service;
	}
	
	public function __call($methodName,$args){
		if( preg_match('/^tx.+/',$methodName )){
			return $this->invoke_with_transaction($methodName,$args);
		}else{
			return $this->invokde_without_transaction($methodName,$args);
		}		
	}

 	private function invoke_with_transaction($methodName,$args){
 		echo "handle transaction start <<";
 		$results =  $this->invoke($methodName,$args);
 		echo " >>handle transaction end";
 		return $results;
	}
	
	private function invokde_without_transaction($methodName,$args){
 		$this->invoke($methodName,$args);
	}
	private function invoke($methodName,$args){
		return call_user_func_array(array($this->service, $methodName), $args);
	}
}

test code

1
2
3
4
5
6
$tester = MyClass::createInstance();
echo "\r\n=======================\r\n";
$tester->noTransactionMethod("first","second");
echo "\r\n=======================\r\n";
$tester->txWithTransactionMethod("third","fourth");
echo "\r\n=======================\r\n";

Your refactoring





Format Copy from initial code

or Cancel