*/ protected array $lockingStrategy = [ SemaphoreLockStrategy::class => true, FileLockStrategy::class => true, SimpleLockStrategy::class => true, ]; /** * Add a locking method. * * @param class-string $className */ public function addLockingStrategy(string $className): void { $interfaces = class_implements($className); if (isset($interfaces[LockingStrategyInterface::class])) { $this->lockingStrategy[$className] = true; } else { throw new \InvalidArgumentException('The given class name ' . $className . ' does not implement the required LockingStrategyInterface interface.', 1425990198); } } /** * Remove a locking method. * * @param class-string $className */ public function removeLockingStrategy(string $className): void { unset($this->lockingStrategy[$className]); } /** * Get best matching locking method * * @param string $id ID to identify this lock in the system * @param int-mask-of $capabilities LockingStrategyInterface::LOCK_CAPABILITY_* elements combined with bit-wise OR * @return LockingStrategyInterface Class name for a locking method * @throws LockCreateException if no locker could be created with the requested capabilities */ public function createLocker(string $id, int $capabilities = LockingStrategyInterface::LOCK_CAPABILITY_EXCLUSIVE): LockingStrategyInterface { $queue = new \SplPriorityQueue(); /** @var class-string $method */ foreach ($this->lockingStrategy as $method => $_) { $supportedCapabilities = $capabilities & $method::getCapabilities(); if ($supportedCapabilities === $capabilities) { $queue->insert($method, $method::getPriority()); } } if ($queue->count() > 0) { $className = $queue->top(); // We use 'new' here on purpose! // Locking might be used very early in the bootstrap process, where makeInstance() does not work return new $className($id); } throw new LockCreateException('Could not find a matching locking method with requested capabilities.', 1425990190); } }