master

laravel/framework

Last updated at: 29/12/2023 09:20

Signals.php

TLDR

The Signals class in the Illuminate\Console namespace is responsible for registering and unregistering signal handlers for console applications. It interacts with the SignalRegistry class. It also provides a method to check if signals are available and execute a callback if so.

Methods

__construct($registry)

This is the constructor method that creates a new instance of the Signals class. It takes a SignalRegistry object as a parameter and assigns it to the $registry property.

register($signal, $callback)

This method is used to register a new signal handler. It takes an integer $signal parameter and a callable $callback parameter. It registers the signal and the callback with the SignalRegistry object. It also sets and updates the handlers for the signal.

initializeSignal($signal)

This is a protected method that initializes the signal's existing handler in array format. It takes an integer $signal parameter and checks if the existing handler is callable. If it is, it returns an array containing the existing handler, otherwise it returns null.

unregister()

This method is used to unregister the current signal handlers. It restores the previous handlers and sets them as the current handlers in the SignalRegistry object.

whenAvailable($callback)

This is a static method that executes the given callback if signals are available. It checks if the availability resolver returns true and if so, it calls the callback.

getHandlers()

This is a protected method that returns the registry's handlers. It retrieves the signalHandlers property from the SignalRegistry object.

setHandlers($handlers)

This is a protected method that sets the registry's handlers. It assigns the given handlers to the signalHandlers property of the SignalRegistry object.

resolveAvailabilityUsing($resolver)

This is a static method that sets the availability resolver. It takes a callable resolver as a parameter and assigns it to the availabilityResolver property of the Signals class.

Classes

There are no additional classes in this file.

<?php

namespace Illuminate\Console;

/**
 * @internal
 */
class Signals
{
    /**
     * The signal registry instance.
     *
     * @var \Symfony\Component\Console\SignalRegistry\SignalRegistry
     */
    protected $registry;

    /**
     * The signal registry's previous list of handlers.
     *
     * @var array<int, array<int, callable>>|null
     */
    protected $previousHandlers;

    /**
     * The current availability resolver, if any.
     *
     * @var (callable(): bool)|null
     */
    protected static $availabilityResolver;

    /**
     * Create a new signal registrar instance.
     *
     * @param  \Symfony\Component\Console\SignalRegistry\SignalRegistry  $registry
     * @return void
     */
    public function __construct($registry)
    {
        $this->registry = $registry;

        $this->previousHandlers = $this->getHandlers();
    }

    /**
     * Register a new signal handler.
     *
     * @param  int  $signal
     * @param  callable(int $signal): void  $callback
     * @return void
     */
    public function register($signal, $callback)
    {
        $this->previousHandlers[$signal] ??= $this->initializeSignal($signal);

        with($this->getHandlers(), function ($handlers) use ($signal) {
            $handlers[$signal] ??= $this->initializeSignal($signal);

            $this->setHandlers($handlers);
        });

        $this->registry->register($signal, $callback);

        with($this->getHandlers(), function ($handlers) use ($signal) {
            $lastHandlerInserted = array_pop($handlers[$signal]);

            array_unshift($handlers[$signal], $lastHandlerInserted);

            $this->setHandlers($handlers);
        });
    }

    /**
     * Gets the signal's existing handler in array format.
     *
     * @return array<int, callable(int $signal): void>
     */
    protected function initializeSignal($signal)
    {
        return is_callable($existingHandler = pcntl_signal_get_handler($signal))
            ? [$existingHandler]
            : null;
    }

    /**
     * Unregister the current signal handlers.
     *
     * @return void
     */
    public function unregister()
    {
        $previousHandlers = $this->previousHandlers;

        foreach ($previousHandlers as $signal => $handler) {
            if (is_null($handler)) {
                pcntl_signal($signal, SIG_DFL);

                unset($previousHandlers[$signal]);
            }
        }

        $this->setHandlers($previousHandlers);
    }

    /**
     * Execute the given callback if "signals" should be used and are available.
     *
     * @param  callable  $callback
     * @return void
     */
    public static function whenAvailable($callback)
    {
        $resolver = static::$availabilityResolver;

        if ($resolver()) {
            $callback();
        }
    }

    /**
     * Get the registry's handlers.
     *
     * @return array<int, array<int, callable>>
     */
    protected function getHandlers()
    {
        return (fn () => $this->signalHandlers)
            ->call($this->registry);
    }

    /**
     * Set the registry's handlers.
     *
     * @param  array<int, array<int, callable(int $signal):void>>  $handlers
     * @return void
     */
    protected function setHandlers($handlers)
    {
        (fn () => $this->signalHandlers = $handlers)
            ->call($this->registry);
    }

    /**
     * Set the availability resolver.
     *
     * @param  callable(): bool
     * @return void
     */
    public static function resolveAvailabilityUsing($resolver)
    {
        static::$availabilityResolver = $resolver;
    }
}