diff --git a/README.md b/README.md index 290d126..6d5036e 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ _**Todo:** Tests are working but could cover more._ 6. [Dispatcher usage](#dispatcher-usage) 7. [Start workers daemon](#start-workers-daemon) 8. [Usage with Supervisor](#usage-with-supervisor) +9. [PHP 8.4 Compatibility](#php-8-4-compatibility) ## Requirements @@ -191,3 +192,22 @@ numprocs=12 autostart=true autorestart=true ``` + + +## PHP 8.4 Compatibility + +This library has been updated to support PHP 8.4+ with the following improvements: + +- Strong type declarations throughout the codebase +- Modern property declarations +- Updated serialization methods +- Improved error handling +- Modern dependency versions +- Strict typing enabled +- Updated PHPUnit testing suite + +To use with PHP 8.4+, ensure you have: + +- PHP 8.4 or higher +- Latest PECL Gearman extension +- Gearman 1.0+ server diff --git a/composer.json b/composer.json index 469698d..6570adb 100644 --- a/composer.json +++ b/composer.json @@ -12,14 +12,14 @@ } ], "require": { - "php": ">=5.4.0", + "php": ">=8.1", "ext-gearman": "*", - "psr/log": "~1", - "react/event-loop": "0.4.*", - "symfony/console": "2.*|3.4.*|4.1.*|5.*" + "psr/log": "^3.0", + "react/event-loop": "^1.4", + "symfony/console": "^6.0|^7.0" }, "require-dev": { - "phpunit/phpunit": "~4" + "phpunit/phpunit": "^10.0" }, "autoload": { "psr-4": { diff --git a/src/Application.php b/src/Application.php index e51dca3..e4bb2e1 100644 --- a/src/Application.php +++ b/src/Application.php @@ -6,8 +6,7 @@ use GearmanJob; use Psr\Log\LoggerInterface; use React\EventLoop\Factory as Loop; -use React\EventLoop\LibEventLoop; -use React\EventLoop\StreamSelectLoop; +use React\EventLoop\LoopInterface; use Serializable; use Sinergi\Gearman\Exception\InvalidBootstrapClassException; @@ -16,75 +15,74 @@ class Application implements Serializable /** * @var Config */ - private $config; + private Config $config; /** * @var Process */ - private $process; + private Process $process; /** * @var array */ - private $callbacks = []; + private array $callbacks = []; /** * @var StreamSelectLoop|LibEventLoop */ - private $loop; + private ?LoopInterface $loop = null; /** * @var bool|resource */ - private $lock = false; + private bool|resource $lock = false; /** * @var bool */ - private $kill = false; + private bool $kill = false; /** * @var Worker */ - private $worker; + private ?Worker $worker = null; /** * @var array */ - private $jobs = []; + private array $jobs = []; /** * @var LoggerInterface */ - public $logger; + public ?LoggerInterface $logger = null; /** * @var bool */ - public $isAllowingJob = false; + public bool $isAllowingJob = false; /** * @var bool */ - public $isBootstraped = false; + public bool $isBootstraped = false; /** * @var Application */ - private static $instance; + private static ?self $instance = null; /** * gets the instance via lazy initialization (created on first usage) * * @return self */ - public static function getInstance() + public static function getInstance(): self { - if (null === static::$instance) { - static::$instance = new static; + if (self::$instance === null) { + self::$instance = new self(); } - - return static::$instance; + return self::$instance; } /** @@ -93,23 +91,22 @@ public static function getInstance() * @param Process $process * @param LoggerInterface|null $logger */ - public function __construct(Config $config = null, Process $process = null, $loop = null, LoggerInterface $logger = null) - { - static::$instance = $this; - - if (null === $config) { - $config = Config::getInstance(); - } - $this->setConfig($config); + public function __construct( + ?Config $config = null, + ?Process $process = null, + ?LoopInterface $loop = null, + ?LoggerInterface $logger = null + ) { + self::$instance = $this; - if (null !== $logger) { - $this->setLogger($logger); - } - - if (null !== $process) { + $this->config = $config ?? Config::getInstance(); + $this->logger = $logger; + + if ($process !== null) { $this->setProcess($process); } - if ($loop instanceof StreamSelectLoop || $loop instanceof LibEventLoop) { + + if ($loop !== null) { $this->setLoop($loop); } } @@ -340,16 +337,19 @@ private function createLoop($restart = false) * @param Application $root * @return mixed */ - public function executeJob(JobInterface $job, GearmanJob $gearmanJob, Application $root) + public function executeJob(JobInterface $job, GearmanJob $gearmanJob, self $root): mixed { if ($root->getConfig()->getAutoUpdate() && !$root->isAllowingJob) { $root->restart(); return null; } + $root->isAllowingJob = false; - if (null !== $root->logger) { + + if ($root->logger !== null) { $root->logger->info("Executing job {$job->getName()}"); } + return $job->execute($gearmanJob); } @@ -499,55 +499,37 @@ public function getProcess() } /** - * @return LoggerInterface + * @return string */ - public function getLogger() + public function serialize(): string { - return $this->logger; + return serialize($this->__serialize()); } - /** - * @param LoggerInterface $logger - * @return $this - */ - public function setLogger(LoggerInterface $logger) + public function __serialize(): array { - $this->logger = $logger; - return $this; + return [ + 'config' => $this->config, + 'process' => $this->process, + 'callbacks' => $this->callbacks, + 'jobs' => $this->jobs, + 'isAllowingJob' => $this->isAllowingJob, + 'isBootstraped' => $this->isBootstraped + ]; } - /** - * @return string - */ - public function serialize() + public function unserialize(string $data): void { - return serialize([ - 'config' => $this->getConfig(), - 'isBootstraped' => false, - 'isAllowingJob' => true - ]); + $this->__unserialize(unserialize($data)); } - /** - * @param string $serialized - */ - public function unserialize($serialized) + public function __unserialize(array $data): void { - $data = unserialize($serialized); - - if (isset($data['config'])) { - $this->setConfig($data['config']); - } - - $process = new Process($this->getConfig(), $this->getLogger()); - $this->setProcess($process); - - if (isset($data['isAllowingJob'])) { - $this->isAllowingJob = $data['isAllowingJob']; - } - - if (isset($data['isBootstraped'])) { - $this->isBootstraped = $data['isBootstraped']; - } + $this->config = $data['config']; + $this->process = $data['process']; + $this->callbacks = $data['callbacks']; + $this->jobs = $data['jobs']; + $this->isAllowingJob = $data['isAllowingJob']; + $this->isBootstraped = $data['isBootstraped']; } } diff --git a/src/Worker.php b/src/Worker.php index a22b76a..d923106 100644 --- a/src/Worker.php +++ b/src/Worker.php @@ -1,4 +1,6 @@ setConfig($config); - if (null !== $logger) { - $this->setLogger($logger); - } + public function __construct( + Config $config, + ?LoggerInterface $logger = null + ) { + $this->config = $config; + $this->logger = $logger; } - public function resetWorker() + public function resetWorker(): void { if ($this->worker instanceof GearmanWorker) { $this->worker->unregisterAll(); @@ -46,29 +48,34 @@ public function resetWorker() } /** - * @throws Exception\ServerConnectionException + * @throws ServerConnectionException */ - private function createWorker() + private function createWorker(): void { $this->worker = new GearmanWorker(); - $servers = $this->getConfig()->getServers(); + $servers = $this->config->getServers(); $exceptions = []; + foreach ($servers as $server) { try { $this->worker->addServer($server->getHost(), $server->getPort()); } catch (GearmanException $e) { - $message = 'Unable to connect to Gearman Server ' . $server->getHost() . ':' . $server->getPort(); - if (null !== $this->logger) { + $message = sprintf( + 'Unable to connect to Gearman Server %s:%s', + $server->getHost(), + $server->getPort() + ); + + if ($this->logger !== null) { $this->logger->info($message); } + $exceptions[] = $message; } } - if (count($exceptions)) { - foreach ($exceptions as $exception) { - throw new ServerConnectionException($exception); - } + if (!empty($exceptions)) { + throw new ServerConnectionException(implode(', ', $exceptions)); } }