This article brings the content is about YII2 development: How to use similar closures to encapsulate the transaction, there is a certain reference value, the need for friends can refer to, I hope to help you.
When performing transactions in the controller, the general code is as follows:
$transaction = Yii:: $app->db->begintransaction (); try { //Some business code $transaction->commit ();} catch (\ Exception $e) { $transaction->rollback (); Throw $e;}
So I was thinking, this code structure, only//Some business code this part is not the same, but to repeat many times, this is not very redundant? And no! Good! See! , so I tried to find a solution, initially found a similar question in the Stackflow, there is a plan to do in the model package, but there are certain problems, such as the creation of nested transactions, etc., interested can click here to see the question and answer.
Our Yii framework gives a method transaction, at first glance, seems unable to solve the problem of the transfer of the parameters, we do not care, look down, the method is called the following way:
Yii:: $app->db->transaction (function () { //Some business code});
Let's take a look at the source code for this method
/** * Executes callback provided in a transaction. * * @param callable $callback A valid PHP callback that performs the job. Accepts connection instance as parameter. * @param string|null $isolationLevel The isolation level to use for this transaction. * See [[Transaction::begin ()]] for details. * @throws \exception|\throwable If there is any Exception during query. In this case the transaction is rolled back. * @return Mixed result of callback function */public function transaction (callable $callback, $isolationLevel = null) { $transaction = $this->begintransaction ($isolationLevel); $level = $transaction->level; try {$result = Call_user_func ($callback, $this); if ($transaction->isactive && $transaction->level = = = $level) {$transaction->commit (); }} catch (\exception $e) {$this->rollbacktransactiononlevel ($transaction, $level); Throw $e; } catch (\throwable $e) {$this->rollbacktranSactiononlevel ($transaction, $level); Throw $e; } return $result;}
This method accepts a callback function and the isolation level of the transaction,
From here we see that although this method solves duplicate code, there are still several problems that are not resolved:
First, this method throws an exception that we need to handle outside the receiver, and we can't throw it directly, which is unfriendly to the client.
Second: There is no logging behavior, even if the problem is not easy to exclude.
Third: Actually still is the first question, if we need to deal with each exception, in the transaction method and then nested a layer of try...catch ..., then and no encapsulation seems to be no different?
According to the method can be extended non-modifiable principle, we should in our own public methods to overload this method, the overloaded code is as follows:
public static function Transactionexecute (callable $function, $level =null) { try{ \yii:: $app->db-> Transaction ($function, $level);} catch (\exception $e) { //log \yii::error ($e->getmessage ()); This can be understood as throwing a custom exception class. (new Self ())->returnwaytip (1004, ' trans exception error ');} }
And then back to the question of how to send the arguments, we can use closures and post a pseudo-code, as follows:
//perform transaction publicfunction::transactionexecute (function () use ($token _reward, $ Reward_info) {//Business code $token _reward->save (0); Msghelper::send ($reward _info[' post_id '), Msghelper::someone_finish_reward, $reward _info); });