Запустить метод в отдельном потоке

У меня есть сервер с методом SendToAll ($ message). Мне нужен отдельный поток, который будет запускать этот метод (SendToAll) каждую секунду. Я использую pthreads.

class Sender extends Thread
{
public function __construct($server)
{
$this->server = $server;
}

public function run()
{
for (;;) {
$this->server->SendForAll("Hello");
sleep(1);
}
}
}
}

Я создал объект моего сервера и попытался поместить его в конструкцию моего Отправителя.

<?php
require_once('includes.php');

runServer();

function runServer()
{
$server = new WssService("0.0.0.0", 9001);
$asyncOp = new Sender($server);

try {
$asyncOp->start();
$server->StartServer();
}catch (Exception $e) {
echo $e->getMessage();
runServer();
}
}

Но у меня ошибка

Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Clos
ure' is not allowed' in D:\xampp\htdocs\admin_p\classes\AsyncStorage.php:6
Stack trace:
#0 D:\xampp\htdocs\admin_p\classes\AsyncStorage.php(6): Sender::__construct()
#1 D:\xampp\htdocs\admin_p\ss.php(9): Sender->__construct(Object(WssService))
#2 D:\xampp\htdocs\admin_p\ss.php(4): runServer()
#3 {main}
thrown in D:\xampp\htdocs\admin_p\classes\AsyncStorage.php on line 6

Постскриптум Извините, английский — это не мой родной язык.

class WssService
{
public $connects_storage = array();
private $server = null;
private $logger = null;
private $writer = null;
public $loop = null;

public function __construct($URI, $port)
{

$this->connected_users = array();
$this->loop = \React\EventLoop\Factory::create();
$this->Logger = new \Zend\Log\Logger();
$this->writer = new Zend\Log\Writer\Stream("php://output");
$this->Logger->addWriter($this->writer);
$this->server = new WebSocketServer("tcp://" . $URI . ":" . $port, $this->loop, $this->Logger);

$this->server->on("connect", function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Connected " . $user->getIp()));
array_push($this->connects_storage,$user);
});

$this->server->on("disconnect", function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Disconnected " . $user->getIp()));
});

$this->server->on("message", function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
$s_user->sendString($message);
});
}

public function StartServer(){
$this->server->bind();
$this->loop->run();
}

public function SendForAll($message){
foreach($this->connects_storage as $client){
$client->sendString($message);
}
}
}

Обновлен метод SendForAll ()

public function SendForAll($message){
echo var_export($message,true) .PHP_EOL;
echo var_dump($this->connects_storage).PHP_EOL;

if (count($this->connects_storage) > 0) {
foreach ($this->connects_storage as $client) {
$client->sendString($message);
}
} else echo "There are empty storage";
}

0

Решение

Ваш WssService объект не сериализуем. Чтобы сделать это так, сделайте $URL а также $port переменные-члены, переместите инициализацию в init() метод и реализовать __sleep() а также __wakeup() методы:

class WssService
{
protected $URI, $port;
public $connects_storage = array();
private $server = null;
private $logger = null;
private $writer = null;
public $loop = null;

public function __construct($URI, $port)
{
$this->URI = $URI;
$this->port = $port;
$this->init();
}
protected function init() {
$this->connected_users = array();
$this->loop = \React\EventLoop\Factory::create();
$this->Logger = new \Zend\Log\Logger();
$this->writer = new Zend\Log\Writer\Stream("php://output");
$this->Logger->addWriter($this->writer);
$this->server = new WebSocketServer("tcp://" . $this->URI . ":" . $this->port, $this->loop, $this->Logger);

$this->server->on("connect", function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Connected " . $user->getIp()));
array_push($this->connects_storage,$user);
});

$this->server->on("disconnect", function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Disconnected " . $user->getIp()));
});

$this->server->on("message", function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
$s_user->sendString($message);
});
}

public function StartServer(){
$this->server->bind();
$this->loop->run();
}

public function SendForAll($message){
foreach($this->connects_storage as $client){
$client->sendString($message)
}
}
public function __sleep() {
return array('URI', 'port');
}
public function __wakeup() {
$this->init();
}
}

__sleep() говорит сериализатору только сериализоваться $URI а также $port переменные, это все, что вам нужно вызвать init() в __wakeup() во время десериализации.

-1

Другие решения

$this->server->on("connect", function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Connected " . $user->getIp()));
array_push($this->connects_storage,$user);
});

$this->server->on("disconnect", function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Disconnected " . $user->getIp()));
});

$this->server->on("message", function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
$s_user->sendString($message);
});

Анонимные функции / замыкания не могут быть сериализованы. Вам нужно будет найти способ хранить их по-разному.

Редактировать: у меня ушло некоторое время, чтобы протестировать этот код (оказывается, вы не можете использовать pthreads с последней версией PHP). В любом случае я смог решить вашу проблему, выполнив следующие действия:

Замените код выше на:

$this->server->on("connect", new Jeremeamia\SuperClosure\SerializableClosure(function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Connected " . $user->getIp()));
array_push($this->connects_storage,$user);
}));

$this->server->on("disconnect", new Jeremeamia\SuperClosure\SerializableClosure(function (WebSocketTransportInterface $user) {
$this->Logger->notice((" Disconnected " . $user->getIp()));
}));

$this->server->on("message", new Jeremeamia\SuperClosure\SerializableClosure(function (WebSocketTransportInterface $s_user, WebSocketMessageInterface $message) {
$s_user->sendString($message);
}));

После этого вам нужно будет включить правильное библиотека и, возможно, включить правильные файлы (я так или иначе не могу заставить композитора правильно загружать вещи)

-1