pmmp / ext-pmmpthread

Fork of https://github.com/krakjoe/pthreads with a revamped API and PHP 8.1+ support
Other
81 stars 17 forks source link

Strings/ints turn into "UNKNOWN:0" if you use them in an async closure function #130

Closed J1b1x closed 1 year ago

J1b1x commented 1 year ago

Reproducing Code

public function initializePlayer(Player $player): void{
    $name = $player->getName();
    $xuid = $player->getXuid();
    var_dump($name); //Jibix YT
    async(function (Medoo $medoo) use ($xuid, $name): void{
        var_dump($name); //UNKNOWN:0
        if (!$medoo->has("users", ["xuid" => $xuid])) $medoo->insert('users', [
            'xuid' => $xuid,
            'name' => $name
        ]);
    }, function () use ($name): void{
        if (($player = Server::getInstance()->getPlayerExact($name)) !== null) session($player)->loadData();
    });
}

You can find the code i use for async closures (like the async function) etc. here: https://github.com/J1b1x/AsyncMedoo/blob/d79a557fa8c65b10aae2dde335feefaf959e21f0/src/Jibix/AsyncMedoo/util/Functions.php#L10

Expected Output

"Jibix YT"

Actual Output

"UNKNOWN:0"

dktapps commented 1 year ago

Does it reproduce if you make the onRun closures static?

I'm currently unable to reproduce this, so I'm going to need some help to narrow down the cause.

J1b1x commented 1 year ago
final class Main extends PluginBase{

    protected function onEnable(): void{
        $test = "Test";
        $this->runTest(static function () use ($test): string{
            var_dump($test);
            return $test;
        });
    }

    private function runTest(Closure $task): void{
        $this->getServer()->getAsyncPool()->submitTask(new AsyncClosureTask(static function () use ($task): void{
            var_dump($task); //UNKNOWN:0
        }));
    }
}

class AsyncClosureTask extends AsyncTask{

    public function __construct(private Closure $onRun){}

    public function onRun(): void{
        ($this->onRun)();
    }
}
dktapps commented 1 year ago

Thanks, this reproduces.

Isolated test case (runnable without PocketMine):

<?php

use pmmp\thread\Runnable;
use pmmp\thread\Worker;
use pmmp\thread\Thread;

//require_once __DIR__ . "/vendor/autoload.php";

class AsyncClosureTask extends Runnable{

    public function __construct(private \Closure $onRun){}

    public function run(): void{
        ($this->onRun)();
    }
}

$worker = new Worker();
$worker->start(Thread::INHERIT_ALL);

$test = "Test";
$task = static function () use ($test): void{
    var_dump($test);
};
$wrapper = static function () use ($task): void{
    var_dump($task); //UNKNOWN:0
};
$worker->stack(new AsyncClosureTask($wrapper));

This actually segfaults in my test rather than dumping UNKNOWN, but it doesn't matter - a bug has been reproduced.

dktapps commented 1 year ago

Looks like this is specific to PHP 8.2.

dktapps commented 1 year ago

Fixed by 69db2fc60e586977fbfb313ba8356ab18c7590ad.