Yii2 frame the pit of torture

Time:2020-9-30

A little gossip

It’s been a year since I wrote my last blog. Before I start to write, I always feel a deep sense of guilt. Tormented by it for a long time, finally, or, started.

Something to celebrateI started working out recently. It’s really refreshing (not) to (like) exploding (dead) every day for 45 minutes of spinning and swimming every day.

All right, the bullshit is over and we’re on the right track.


 

Activerecord was written inexplicably?

Preparation knowledge

  1. ActiveRecordThe basic usage of. If you don’t understand, please refer to here.

Code site

/**
 * @property integer $id
 * @property string $name
 * @property string $detail
 * @property double $price
 * @property integer $area
 **/
class OcRoom extends ActivieRecord
{
    ...
}

// fetch an object: ocroom().
    ->Select (['id ')] // only the' ID 'column is retrieved
    ->where(['id'=>20])
    ->one();
$room > save(); // save, you will find that other fields in this line have been written as default values.

Summarize the problem

The problem with this example is:

  1. I took a line out of the database, which is in the code$room, but only took it outidThe other fields are the default values.
  2. When I$room->save()The default fields are also saved to the database. what!?
  3. That is to say, when you want to save resources and not extract all the fields,It must be noted that it cannot be saved, otherwise, a lot of data will be inexplicably modified to the default value.

resolvent

However, what solutions do we have? Several ideas are provided

  1. Always pay attention to avoid not completely taking outActiveRecordThe preservation of.
  2. Modification or inheritanceActiveRecord, so that when the object isfind()New, and the field is not completely taken out, callsave()Method, throw an exception.
  3. Modification or inheritanceActiveRecord, so that when the object isfind()New, and the field is not completely taken out, callsave()Method, only the extracted fields are saved, and other fields are ignored.

 

Is your transaction effective?

Code site

/**
 * @property integer $id
 * @property string $name
 **/
class OcRoom extends ActiveRecord
{
    public function rules()
    {
        return [['name','string','min'=>2,'max'=>10]];
    }
    ...
}
class OcHouse extends ActiveRecord
{
    public function rules()
    {
        return [['name','string','max'=>10]];
    }
    ...
}

$a = new OcRoom();
$a - > name = '; // name is an empty string, which does not meet the rules() condition.

$b = new OcHouse();
$B - > name ='My room '; // name is legal and can be saved.

$transaction = Yii::$app->db->beginTransaction();
try{
    The $a - > save(); // name field is illegal and cannot be verified. In the validate() phase, false has been returned. The database storage step will not be performed, so no exception will be thrown.
    $B - > save(); // name field is legal and can be saved normally.

    $transaction > commit(); // after submitting, it is found that $a failed to be saved, but $B was saved successfully.
}
catch (Exception $e) 
{
    Yii::error($e->getTraceAsString(),__METHOD__);
    $transaction->rollBack();
}

Problem summary

The problem with this code is:

  1. You know$transactionThe significance of the existence is to ensure that the whole database storage code is either all successful or all failure.
  2. Obviously, in this case,transactionIt did not achieve the desired effect:$abecausevalidate()None, so$transation->commit()You don’t report a mistake.

resolvent

stay$transationBlock, all of themsave()The return value should be determined if it isfalse, the exception is thrown directly.


 

Y-m’s not recognized?

Code site

OcRenterBill extends ActiveRecord
{
    public function rules()
    {
        return [
            ['start_time','date','format'=>'Y-m-d'],
        ];
    }
}

$a = new OcRenterBill();
$a = '2015-09-12';
$a - > save(); // an error will be reported, saying that the format is incorrect

Problem summary

If the Yii framework reports an error at the beginning, this is not a hole. What’s more, when I developed it on MAC, it worked perfectly. When it was released to the online environment (Ubuntu), it would pop up “property start”_ Invalid time format “. However, referring to the official documents, it is found that this format is allowed official documents.

Ah ah ah. All kinds of trial and error, and finally found that if thephp:Y-m-dThe world is clean. So, if you have this problem, thank me.


 

Memory leak

Code site

public static function actionTest() {
        $total = 10;
        ('start memory'. Memory_ get_ usage());
        while($total){
            $ret=User::findOne(['id'=>910002]);
            ('end memory '. Memory_ get_ usage());
            unset($ret);
            $total--;
        }
    }

The memory of the above code is growing all the time. According to the original idea, if the variables are released, the memory will not grow all the time even if it grows. This is because memory is released once per loop.

Analysis of the problem, the above code involves the operation of the database, and we know that many places in the database can cause memory leakage. So first block database related operations, I handwritten a native database query operation, found that the memory is normal, no problem.

$dsn = "mysql:dbname=test;host=localhost";
$db_user = 'root';
$db_pass = 'admin';
//Inquiry
$sql = "select * from buyer";
$res = $pdo->query($sql);
foreach($res as $row) {
    echo $row['username'].'';
}

At this time, the answer is coming out — it is the yii2 framework that has gone wrong

Since we know that the location problem is the yii2 framework problem, we can further narrow the problem.

public static function actionTest() {
        $total = 10;
        ('start memory'. Memory_ get_ usage());
        while($total){
            $ret= new User();
            ('end memory '. Memory_ get_ usage());
            unset($ret);
            $total--;
        }
    }

Memory is still growing. At this time, I tested another yii2 class and found that the memory did not grow. This can be associated with the new object when yii2 itself executed what operation, and then caused a memory leak. What method is implemented when it is new… How to construct pairs__ construct 。 Then I checked the object step by step from the model and found that there was no leak.

At this time, we might as well change our thinking. Since it is the leakage under the yii2 framework, it must be the unique function of yii2. What function is unique to yii2 and will be executed when the object is new?

Behavior found that my model class really has useful behavior

public function behaviors()
    {
        return [
            TimestampBehavior::class,
        ];
    }

The most common code. We know that the last thing the action calls is yii\base\Component->attachBehaviors finally positioned.

private function attachBehaviorInternal($name, $behavior)
    {
        if (!($behavior instanceof Behavior)) {
            $behavior = Yii::createObject($behavior);
        }
        if (($name)) {
            $behavior->attach($this);
            $this->_behaviors[] = $behavior;
        } else {
            if (isset($this->_behaviors[$name])) {
                $this->_behaviors[$name]->detach();
            }
            $behavior->attach($this);
            $this->_behaviors[$name] = $behavior;
        }
 
        return $behavior;
    }

We observed this code and found that he had imported himself into $behavior->attach ($this), and finally called yii\base\Behavior->attach.

public function attach($owner)
    {
        $this->owner = $owner;
        foreach ($this->events() as $event => $handler) {
            $owner->on($event, ($handler) ? [$this, $handler] : $handler);
        }
    }

Problem summary

At this time, the answer is ready to come out. Yii2, in order to realize the function of behavior, transmits its own this in order to register events, trigger events, and release events. This leads to a circular reference problem. Therefore, the refcount of the object is not zero and cannot be recycled.

The next thing is easy. Try replacing the query with the original connection. Sure enough, the memory is rising very slowly, which can be said to be the normal phenomenon. Now the memory is about 50m, and the CPU is stable at about 7%.

After code optimization, run the script again, about 1 minute, and the script is finished. The point is that no more memory errors will be reported. Therefore, in the future, we still need to think deeply. Dare to question. In the future, if you encounter this kind of memory error, you must first check whether your code has a memory leak. Don’t try to set up PHP memory first. This will only cure the symptoms, not the root cause.

summary

1. In terms of development speed, with the help of GII scaffold, code can be generated quickly, that is to say, to build a system that can be added, deleted, modified and checked, a line of code may not need to be written. Moreover, jQuery and bootstrap are integrated, so special effects and styles do not need to be written. This is a great benefit for the back-end programmers whose design and aesthetic abilities are generally poor. However, in the trend of complete separation of the front and rear ends of yii2, the coupling between the front and rear ends of yii2 is somewhat heavy.

2. In terms of readability, Yii will not over design the code in order to rigidly follow a certain design pattern. Basically, classes can jump to read the source code without the help of third-party components in the IDE. Yii is a little better than laravel.

3. In terms of the open source ecosystem, Yii needs a strong ability of Google and the ability to read English documents because there are few people in Yii.

It is undeniable that Yii is an excellent development framework, which is worth learning by PHP developers. The process of stepping on the pit is also a kind of growth and accumulation. Finally, I wish PHP partners good health and success.

 

END

Recommended Today

Singularity iPhone version officially launched

Recently, I haven’t updated my short book, technology blog, CocoaChina, etc. I’ve been busy developing my own product singularity app. I hope to solve our technical problems in this high-quality “app ape” product, so that more people know the singularity. We dig high-quality Internet technology articles every day for you to recommend (currently, it supports […]