opis / closure

Serialize closures (anonymous functions)

Home Page:https://opis.io/closure

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"Using $this when not in object context" in 3.5.4

tormit opened this issue · comments

After updating to 3.5.4, I'm getting error "Using $this when not in object context in closure:".

For example:
Using $this when not in object context in closure:

//function () use ($changedData, $oldData, $zchanged) {
                    \Illuminate\Support\Facades\DB::transaction(
                        function () use ($changedData, $oldData, $zchanged) {
                            $this->refresh();
                            if (!$this->exists) {
                                return;
                            }

                            if (!$this->activity_name) {
                                return;
                            }
                        // ....
});

Tried both on PHP 7.1 and 7.4.

@tormit please provide a simple example so we can reproduce the issue. thanks!

Are you sure it was that upgrade. What other dependencies did you also upgrade at the same time?

I'll try to provide working example soon.

As soon as I downgraded this package to 3.5.3, problem went away.
I tried with 3.5.4 now when all other packages are also up-to-date and problem still appears.

Right, so every other package was at exactly the same version when you downgraded, apart from this package?

Yes, I tried with older set of other packages and latest set of other packages. Whenever I switch opis/closure to 3.5.4, it's broken.

@tormit Normally, we should serialize the closure's bound object every time a closure is serialized, but that would sometime require to wrap/unwrap very large objects. That's why we decided to serialize the bound object only when we detect that $this is used inside the serialized closure. If you put a $self = $this inside the serialized closure, just before \Illuminate\Support\Facades\DB::transaction, than opis/closure will serialize the bound object too.

function () use ($changedData, $oldData, $zchanged) {
       $self = $this;
                    \Illuminate\Support\Facades\DB::transaction(
                        function () use ($changedData, $oldData, $zchanged) {
                            $this->refresh();
                            if (!$this->exists) {
                                return;
                            }

                            if (!$this->activity_name) {
                                return;
                            }
                        // ....
         }
});

In v3.5.4 we made some improvements to our parser in order to get rid of some false-positives regarding class scope. The behaviour in v3.5.4 is correct because $this is not used inside the serialized closure itself but inside another closure which expects to inherit the bound object from the parent closure. But because the bound object is serialized only when $this is used inside the serialized closure itself you get an error.

Provided hack seems to works. Thanks for help!