Explorar o código

Add property types to all properties where possible

Jordi Boggiano %!s(int64=3) %!d(string=hai) anos
pai
achega
0dac87975c
Modificáronse 36 ficheiros con 201 adicións e 250 borrados
  1. 3 3
      doc/04-extending.md
  2. 13 8
      src/Monolog/ErrorHandler.php
  3. 2 2
      src/Monolog/Formatter/ElasticaFormatter.php
  4. 3 5
      src/Monolog/Handler/AmqpHandler.php
  5. 10 13
      src/Monolog/Handler/FilterHandler.php
  6. 23 17
      src/Monolog/Handler/FingersCrossedHandler.php
  7. 2 5
      src/Monolog/Handler/FormattableHandlerTrait.php
  8. 18 28
      src/Monolog/Handler/NewRelicHandler.php
  9. 8 2
      src/Monolog/Handler/PushoverHandler.php
  10. 11 12
      src/Monolog/Handler/RedisHandler.php
  11. 7 8
      src/Monolog/Handler/RedisPubSubHandler.php
  12. 12 13
      src/Monolog/Handler/SamplingHandler.php
  13. 4 7
      src/Monolog/Handler/Slack/SlackRecord.php
  14. 5 10
      src/Monolog/Handler/SocketHandler.php
  15. 5 9
      src/Monolog/Handler/StreamHandler.php
  16. 1 1
      src/Monolog/Handler/SyslogUdpHandler.php
  17. 3 6
      src/Monolog/Handler/TelegramBotHandler.php
  18. 10 14
      src/Monolog/Logger.php
  19. 7 8
      src/Monolog/Processor/WebProcessor.php
  20. 1 1
      tests/Monolog/Formatter/LineFormatterTest.php
  21. 1 1
      tests/Monolog/Formatter/ScalarFormatterTest.php
  22. 1 1
      tests/Monolog/Handler/BufferHandlerTest.php
  23. 1 1
      tests/Monolog/Handler/ChromePHPHandlerTest.php
  24. 7 15
      tests/Monolog/Handler/DynamoDbHandlerTest.php
  25. 1 1
      tests/Monolog/Handler/FirePHPHandlerTest.php
  26. 3 2
      tests/Monolog/Handler/HandlerWrapperTest.php
  27. 3 6
      tests/Monolog/Handler/PHPConsoleHandlerTest.php
  28. 4 2
      tests/Monolog/Handler/PushoverHandlerTest.php
  29. 0 7
      tests/Monolog/Handler/RedisHandlerTest.php
  30. 0 7
      tests/Monolog/Handler/RedisPubSubHandlerTest.php
  31. 1 1
      tests/Monolog/Handler/RotatingFileHandlerTest.php
  32. 26 27
      tests/Monolog/Handler/SocketHandlerTest.php
  33. 0 2
      tests/Monolog/Handler/ZendMonitorHandlerTest.php
  34. 1 1
      tests/Monolog/Processor/WebProcessorTest.php
  35. 1 1
      tests/Monolog/PsrLogCompatTest.php
  36. 3 3
      tests/Monolog/SignalHandlerTest.php

+ 3 - 3
doc/04-extending.md

@@ -26,9 +26,9 @@ use Monolog\Handler\AbstractProcessingHandler;
 
 class PDOHandler extends AbstractProcessingHandler
 {
-    private $initialized = false;
-    private $pdo;
-    private $statement;
+    private bool $initialized = false;
+    private PDO $pdo;
+    private PDOStatement $statement;
 
     public function __construct(PDO $pdo, $level = Level::Debug, bool $bubble = true)
     {

+ 13 - 8
src/Monolog/ErrorHandler.php

@@ -26,28 +26,33 @@ use Psr\Log\LogLevel;
  */
 class ErrorHandler
 {
-    private LoggerInterface $logger;
-
     private Closure|null $previousExceptionHandler = null;
+
     /** @var array<class-string, LogLevel::*> an array of class name to LogLevel::* constant mapping */
     private array $uncaughtExceptionLevelMap = [];
 
-    /** @var callable|true|null */
-    private $previousErrorHandler = null;
+    /** @var Closure|true|null */
+    private Closure|bool|null $previousErrorHandler = null;
+
     /** @var array<int, LogLevel::*> an array of E_* constant to LogLevel::* constant mapping */
     private array $errorLevelMap = [];
+
     private bool $handleOnlyReportedErrors = true;
 
     private bool $hasFatalErrorHandler = false;
+
     private string $fatalLevel = LogLevel::ALERT;
+
     private string|null $reservedMemory = null;
+
     /** @var mixed|null */
     private $lastFatalTrace = null;
+
     private const FATAL_ERRORS = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
 
-    public function __construct(LoggerInterface $logger)
-    {
-        $this->logger = $logger;
+    public function __construct(
+        private LoggerInterface $logger
+    ) {
     }
 
     /**
@@ -108,7 +113,7 @@ class ErrorHandler
         $prev = set_error_handler([$this, 'handleError'], $errorTypes);
         $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
         if ($callPrevious) {
-            $this->previousErrorHandler = $prev ?: true;
+            $this->previousErrorHandler = $prev !== null ? $prev(...) : true;
         } else {
             $this->previousErrorHandler = null;
         }

+ 2 - 2
src/Monolog/Formatter/ElasticaFormatter.php

@@ -27,9 +27,9 @@ class ElasticaFormatter extends NormalizerFormatter
     protected string $index;
 
     /**
-     * @var ?string Elastic search document type
+     * @var string|null Elastic search document type
      */
-    protected $type;
+    protected string|null $type;
 
     /**
      * @param string  $index Elastic Search index name

+ 3 - 5
src/Monolog/Handler/AmqpHandler.php

@@ -14,6 +14,7 @@ namespace Monolog\Handler;
 use Monolog\Level;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\JsonFormatter;
+use Monolog\LevelName;
 use PhpAmqpLib\Message\AMQPMessage;
 use PhpAmqpLib\Channel\AMQPChannel;
 use AMQPExchange;
@@ -21,10 +22,7 @@ use Monolog\LogRecord;
 
 class AmqpHandler extends AbstractProcessingHandler
 {
-    /**
-     * @var AMQPExchange|AMQPChannel $exchange
-     */
-    protected $exchange;
+    protected AMQPExchange|AMQPChannel $exchange;
 
     protected string $exchangeName;
 
@@ -32,7 +30,7 @@ class AmqpHandler extends AbstractProcessingHandler
      * @param AMQPExchange|AMQPChannel $exchange     AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
      * @param string|null              $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only
      */
-    public function __construct($exchange, ?string $exchangeName = null, $level = Level::Debug, bool $bubble = true)
+    public function __construct(AMQPExchange|AMQPChannel $exchange, ?string $exchangeName = null, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true)
     {
         if ($exchange instanceof AMQPChannel) {
             $this->exchangeName = (string) $exchangeName;

+ 10 - 13
src/Monolog/Handler/FilterHandler.php

@@ -11,6 +11,7 @@
 
 namespace Monolog\Handler;
 
+use Closure;
 use Monolog\Level;
 use Monolog\LevelName;
 use Monolog\Logger;
@@ -32,12 +33,11 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
     use ProcessableHandlerTrait;
 
     /**
-     * Handler or factory callable($record, $this)
+     * Handler or factory Closure($record, $this)
      *
-     * @var callable|HandlerInterface
-     * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
+     * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
      */
-    protected $handler;
+    protected Closure|HandlerInterface $handler;
 
     /**
      * Minimum level for logs that are passed to handler
@@ -53,9 +53,9 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
     protected bool $bubble;
 
     /**
-     * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
+     * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
      *
-     * @param callable|HandlerInterface                                                $handler        Handler or factory callable($record|null, $filterHandler).
+     * @param Closure|HandlerInterface                                                 $handler        Handler or factory callable($record|null, $filterHandler).
      * @param int|string|Level|LevelName|array<int|string|Level|LevelName|LogLevel::*> $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
      * @param int|string|Level|LevelName|LogLevel::*                                   $maxLevel       Maximum level to accept, only used if $minLevelOrList is not an array
      * @param bool                                                                     $bubble         Whether the messages that are handled can bubble up the stack or not
@@ -63,15 +63,11 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
      * @phpstan-param value-of<Level::VALUES>|value-of<LevelName::VALUES>|Level|LevelName|LogLevel::*|array<value-of<Level::VALUES>|value-of<LevelName::VALUES>|Level|LevelName|LogLevel::*> $minLevelOrList
      * @phpstan-param value-of<Level::VALUES>|value-of<LevelName::VALUES>|Level|LevelName|LogLevel::* $maxLevel
      */
-    public function __construct($handler, int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency, bool $bubble = true)
+    public function __construct(Closure|HandlerInterface $handler, int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency, bool $bubble = true)
     {
         $this->handler  = $handler;
         $this->bubble   = $bubble;
         $this->setAcceptedLevels($minLevelOrList, $maxLevel);
-
-        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
-            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
-        }
     }
 
     /**
@@ -157,10 +153,11 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
     public function getHandler(LogRecord $record = null): HandlerInterface
     {
         if (!$this->handler instanceof HandlerInterface) {
-            $this->handler = ($this->handler)($record, $this);
-            if (!$this->handler instanceof HandlerInterface) {
+            $handler = ($this->handler)($record, $this);
+            if (!$handler instanceof HandlerInterface) {
                 throw new \RuntimeException("The factory callable should return a HandlerInterface");
             }
+            $this->handler = $handler;
         }
 
         return $this->handler;

+ 23 - 17
src/Monolog/Handler/FingersCrossedHandler.php

@@ -11,6 +11,7 @@
 
 namespace Monolog\Handler;
 
+use Closure;
 use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
 use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
 use Monolog\Level;
@@ -42,33 +43,41 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
     use ProcessableHandlerTrait;
 
     /**
-     * @var callable|HandlerInterface
-     * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
+     * Handler or factory callable($record, $this)
+     *
+     * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
      */
-    protected $handler;
+    protected Closure|HandlerInterface $handler;
+
     protected ActivationStrategyInterface $activationStrategy;
+
     protected bool $buffering = true;
+
     protected int $bufferSize;
+
     /** @var LogRecord[] */
     protected array $buffer = [];
+
     protected bool $stopBuffering;
+
     protected Level|null $passthruLevel = null;
+
     protected bool $bubble;
 
     /**
-     * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
+     * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
      *
-     * @param callable|HandlerInterface              $handler            Handler or factory callable($record|null, $fingersCrossedHandler).
-     * @param int|string|Level|LevelName|LogLevel::* $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated
-     * @param int                                    $bufferSize         How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
-     * @param bool                                   $bubble             Whether the messages that are handled can bubble up the stack or not
-     * @param bool                                   $stopBuffering      Whether the handler should stop buffering after being triggered (default true)
-     * @param int|string|Level|LevelName|LogLevel::* $passthruLevel      Minimum level to always flush to handler on close, even if strategy not triggered
+     * @param Closure|HandlerInterface                    $handler            Handler or factory callable($record|null, $fingersCrossedHandler).
+     * @param int|string|Level|LevelName|LogLevel::*      $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated
+     * @param int                                         $bufferSize         How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+     * @param bool                                        $bubble             Whether the messages that are handled can bubble up the stack or not
+     * @param bool                                        $stopBuffering      Whether the handler should stop buffering after being triggered (default true)
+     * @param int|string|Level|LevelName|LogLevel::*|null $passthruLevel      Minimum level to always flush to handler on close, even if strategy not triggered
      *
      * @phpstan-param value-of<Level::VALUES>|value-of<LevelName::VALUES>|Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy
      * @phpstan-param value-of<Level::VALUES>|value-of<LevelName::VALUES>|Level|LevelName|LogLevel::* $passthruLevel
      */
-    public function __construct($handler, int|string|Level|LevelName|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|LevelName $passthruLevel = null)
+    public function __construct(Closure|HandlerInterface $handler, int|string|Level|LevelName|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|LevelName|null $passthruLevel = null)
     {
         if (null === $activationStrategy) {
             $activationStrategy = new ErrorLevelActivationStrategy(Level::Warning);
@@ -88,10 +97,6 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
         if ($passthruLevel !== null) {
             $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
         }
-
-        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
-            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
-        }
     }
 
     /**
@@ -198,10 +203,11 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
     public function getHandler(LogRecord $record = null): HandlerInterface
     {
         if (!$this->handler instanceof HandlerInterface) {
-            $this->handler = ($this->handler)($record, $this);
-            if (!$this->handler instanceof HandlerInterface) {
+            $handler = ($this->handler)($record, $this);
+            if (!$handler instanceof HandlerInterface) {
                 throw new \RuntimeException("The factory callable should return a HandlerInterface");
             }
+            $this->handler = $handler;
         }
 
         return $this->handler;

+ 2 - 5
src/Monolog/Handler/FormattableHandlerTrait.php

@@ -21,10 +21,7 @@ use Monolog\Formatter\LineFormatter;
  */
 trait FormattableHandlerTrait
 {
-    /**
-     * @var ?FormatterInterface
-     */
-    protected $formatter;
+    protected FormatterInterface|null $formatter = null;
 
     /**
      * @inheritDoc
@@ -41,7 +38,7 @@ trait FormattableHandlerTrait
      */
     public function getFormatter(): FormatterInterface
     {
-        if (!$this->formatter) {
+        if (null === $this->formatter) {
             $this->formatter = $this->getDefaultFormatter();
         }
 

+ 18 - 28
src/Monolog/Handler/NewRelicHandler.php

@@ -12,6 +12,7 @@
 namespace Monolog\Handler;
 
 use Monolog\Level;
+use Monolog\LevelName;
 use Monolog\Utils;
 use Monolog\Formatter\NormalizerFormatter;
 use Monolog\Formatter\FormatterInterface;
@@ -28,41 +29,30 @@ use Monolog\LogRecord;
  */
 class NewRelicHandler extends AbstractProcessingHandler
 {
-    /**
-     * Name of the New Relic application that will receive logs from this handler.
-     *
-     * @var ?string
-     */
-    protected $appName;
-
-    /**
-     * Name of the current transaction
-     *
-     * @var ?string
-     */
-    protected $transactionName;
-
-    /**
-     * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
-     * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
-     */
-    protected bool $explodeArrays;
-
     /**
      * @inheritDoc
      */
     public function __construct(
-        $level = Level::Error,
+        int|string|Level|LevelName $level = Level::Error,
         bool $bubble = true,
-        ?string $appName = null,
-        bool $explodeArrays = false,
-        ?string $transactionName = null
+
+        /**
+         * Name of the New Relic application that will receive logs from this handler.
+         */
+        protected string|null $appName = null,
+
+        /**
+         * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
+         * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
+         */
+        protected bool $explodeArrays = false,
+
+        /**
+         * Name of the current transaction
+         */
+        protected string|null $transactionName = null
     ) {
         parent::__construct($level, $bubble);
-
-        $this->appName       = $appName;
-        $this->explodeArrays = $explodeArrays;
-        $this->transactionName = $transactionName;
     }
 
     /**

+ 8 - 2
src/Monolog/Handler/PushoverHandler.php

@@ -27,16 +27,22 @@ use Monolog\LogRecord;
 class PushoverHandler extends SocketHandler
 {
     private string $token;
+
     /** @var array<int|string> */
     private array $users;
+
     private string $title;
-    /** @var string|int|null */
-    private $user = null;
+
+    private string|int|null $user = null;
+
     private int $retry;
+
     private int $expire;
 
     private Level $highPriorityLevel;
+
     private Level $emergencyLevel;
+
     private bool $useFormattedMessage = false;
 
     /**

+ 11 - 12
src/Monolog/Handler/RedisHandler.php

@@ -14,7 +14,10 @@ namespace Monolog\Handler;
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Level;
+use Monolog\LevelName;
 use Monolog\LogRecord;
+use Predis\Client as Predis;
+use Redis;
 
 /**
  * Logs to a Redis key using rpush
@@ -29,22 +32,18 @@ use Monolog\LogRecord;
  */
 class RedisHandler extends AbstractProcessingHandler
 {
-    /** @var \Predis\Client<\Predis\Client>|\Redis */
-    private $redisClient;
+    /** @var Predis<Predis>|Redis */
+    private Predis|Redis $redisClient;
     private string $redisKey;
     protected int $capSize;
 
     /**
-     * @param \Predis\Client<\Predis\Client>|\Redis $redis   The redis instance
-     * @param string                                $key     The key name to push records to
-     * @param int                                   $capSize Number of entries to limit list size to, 0 = unlimited
+     * @param Predis<Predis>|Redis $redis   The redis instance
+     * @param string               $key     The key name to push records to
+     * @param int                  $capSize Number of entries to limit list size to, 0 = unlimited
      */
-    public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true, int $capSize = 0)
+    public function __construct(Predis|Redis $redis, string $key, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, int $capSize = 0)
     {
-        if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
-            throw new \InvalidArgumentException('Predis\Client or Redis instance required');
-        }
-
         $this->redisClient = $redis;
         $this->redisKey = $key;
         $this->capSize = $capSize;
@@ -70,8 +69,8 @@ class RedisHandler extends AbstractProcessingHandler
      */
     protected function writeCapped(LogRecord $record): void
     {
-        if ($this->redisClient instanceof \Redis) {
-            $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1;
+        if ($this->redisClient instanceof Redis) {
+            $mode = defined('Redis::MULTI') ? Redis::MULTI : 1;
             $this->redisClient->multi($mode)
                 ->rpush($this->redisKey, $record->formatted)
                 ->ltrim($this->redisKey, -$this->capSize, -1)

+ 7 - 8
src/Monolog/Handler/RedisPubSubHandler.php

@@ -14,7 +14,10 @@ namespace Monolog\Handler;
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Level;
+use Monolog\LevelName;
 use Monolog\LogRecord;
+use Predis\Client as Predis;
+use Redis;
 
 /**
  * Sends the message to a Redis Pub/Sub channel using PUBLISH
@@ -29,20 +32,16 @@ use Monolog\LogRecord;
  */
 class RedisPubSubHandler extends AbstractProcessingHandler
 {
-    /** @var \Predis\Client<\Predis\Client>|\Redis */
+    /** @var Predis<Predis>|Redis */
     private $redisClient;
     private string $channelKey;
 
     /**
-     * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance
-     * @param string                                $key   The channel key to publish records to
+     * @param Predis<Predis>|Redis $redis The redis instance
+     * @param string               $key   The channel key to publish records to
      */
-    public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true)
+    public function __construct(Predis|Redis $redis, string $key, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true)
     {
-        if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
-            throw new \InvalidArgumentException('Predis\Client or Redis instance required');
-        }
-
         $this->redisClient = $redis;
         $this->channelKey = $key;
 

+ 12 - 13
src/Monolog/Handler/SamplingHandler.php

@@ -11,6 +11,7 @@
 
 namespace Monolog\Handler;
 
+use Closure;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\LogRecord;
 
@@ -33,28 +34,25 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
     use ProcessableHandlerTrait;
 
     /**
-     * @var HandlerInterface|callable
-     * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
+     * Handler or factory callable($record, $this)
+     *
+     * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
      */
-    protected $handler;
+    protected Closure|HandlerInterface $handler;
 
     protected int $factor;
 
     /**
-     * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
+     * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
      *
-     * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
-     * @param int                       $factor  Sample factor (e.g. 10 means every ~10th record is sampled)
+     * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
+     * @param int                      $factor  Sample factor (e.g. 10 means every ~10th record is sampled)
      */
-    public function __construct($handler, int $factor)
+    public function __construct(Closure|HandlerInterface $handler, int $factor)
     {
         parent::__construct();
         $this->handler = $handler;
         $this->factor = $factor;
-
-        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
-            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
-        }
     }
 
     public function isHandling(LogRecord $record): bool
@@ -83,10 +81,11 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
     public function getHandler(LogRecord $record = null): HandlerInterface
     {
         if (!$this->handler instanceof HandlerInterface) {
-            $this->handler = ($this->handler)($record, $this);
-            if (!$this->handler instanceof HandlerInterface) {
+            $handler = ($this->handler)($record, $this);
+            if (!$handler instanceof HandlerInterface) {
                 throw new \RuntimeException("The factory callable should return a HandlerInterface");
             }
+            $this->handler = $handler;
         }
 
         return $this->handler;

+ 4 - 7
src/Monolog/Handler/Slack/SlackRecord.php

@@ -38,17 +38,17 @@ class SlackRecord
     /**
      * Slack channel (encoded ID or name)
      */
-    private ?string $channel;
+    private string|null $channel;
 
     /**
      * Name of a bot
      */
-    private ?string $username;
+    private string|null $username;
 
     /**
      * User icon e.g. 'ghost', 'http://example.com/user.png'
      */
-    private ?string $userIcon;
+    private string|null $userIcon;
 
     /**
      * Whether the message should be added to Slack as attachment (plain text otherwise)
@@ -71,10 +71,7 @@ class SlackRecord
      */
     private array $excludeFields;
 
-    /**
-     * @var ?FormatterInterface
-     */
-    private $formatter;
+    private FormatterInterface|null $formatter;
 
     private NormalizerFormatter $normalizerFormatter;
 

+ 5 - 10
src/Monolog/Handler/SocketHandler.php

@@ -28,17 +28,12 @@ class SocketHandler extends AbstractProcessingHandler
     private $resource;
     private float $timeout;
     private float $writingTimeout;
-    /** @var ?int */
-    private $lastSentBytes = null;
-    /** @var ?int */
-    private $chunkSize;
+    private int|null $lastSentBytes = null;
+    private int|null $chunkSize;
     private bool $persistent;
-    /** @var ?int */
-    private $errno = null;
-    /** @var ?string */
-    private $errstr = null;
-    /** @var ?float */
-    private $lastWritingAt = null;
+    private int|null $errno = null;
+    private string|null $errstr = null;
+    private float|null $lastWritingAt = null;
 
     /**
      * @param string     $connectionString  Socket connection string

+ 5 - 9
src/Monolog/Handler/StreamHandler.php

@@ -24,22 +24,18 @@ use Monolog\LogRecord;
  */
 class StreamHandler extends AbstractProcessingHandler
 {
-    /** @const int */
     protected const MAX_CHUNK_SIZE = 2147483647;
-    /** @const int 10MB */
+    /** 10MB */
     protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024;
     protected int $streamChunkSize;
     /** @var resource|null */
     protected $stream;
-    /** @var ?string */
-    protected $url = null;
-    /** @var ?string */
-    private $errorMessage = null;
-    /** @var ?int */
-    protected $filePermission;
+    protected string|null $url = null;
+    private string|null $errorMessage = null;
+    protected int|null $filePermission;
     protected bool $useLocking;
     /** @var true|null */
-    private ?bool $dirCreated = null;
+    private bool|null $dirCreated = null;
 
     /**
      * @param resource|string $stream         If a missing path can't be created, an UnexpectedValueException will be thrown on first write

+ 1 - 1
src/Monolog/Handler/SyslogUdpHandler.php

@@ -39,7 +39,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler
     protected UdpSocket $socket;
     protected string $ident;
     /** @var self::RFC* */
-    protected $rfc;
+    protected int $rfc;
 
     /**
      * @param  string                    $host     Either IP/hostname or a path to a unix socket (port must be 0 then)

+ 3 - 6
src/Monolog/Handler/TelegramBotHandler.php

@@ -64,21 +64,18 @@ class TelegramBotHandler extends AbstractProcessingHandler
      * The kind of formatting that is used for the message.
      * See available options at https://core.telegram.org/bots/api#formatting-options
      * or in AVAILABLE_PARSE_MODES
-     * @var ?string
      */
-    private $parseMode;
+    private string|null $parseMode;
 
     /**
      * Disables link previews for links in the message.
-     * @var ?bool
      */
-    private $disableWebPagePreview;
+    private bool|null $disableWebPagePreview;
 
     /**
      * Sends the message silently. Users will receive a notification with no sound.
-     * @var ?bool
      */
-    private $disableNotification;
+    private bool|null $disableNotification;
 
     /**
      * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages.

+ 10 - 14
src/Monolog/Logger.php

@@ -11,6 +11,7 @@
 
 namespace Monolog;
 
+use Closure;
 use DateTimeZone;
 use Monolog\Handler\HandlerInterface;
 use Monolog\Processor\ProcessorInterface;
@@ -101,8 +102,6 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * This is only bumped when API breaks are done and should
      * follow the major version of the library
-     *
-     * @var int
      */
     public const API = 3;
 
@@ -111,7 +110,7 @@ class Logger implements LoggerInterface, ResettableInterface
     /**
      * The handler stack
      *
-     * @var HandlerInterface[]
+     * @var list<HandlerInterface>
      */
     protected array $handlers;
 
@@ -122,16 +121,13 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * @var array<(callable(LogRecord): LogRecord)|ProcessorInterface>
      */
-    protected $processors;
+    protected array $processors;
 
     protected bool $microsecondTimestamps = true;
 
     protected DateTimeZone $timezone;
 
-    /**
-     * @var callable|null
-     */
-    protected $exceptionHandler;
+    protected Closure|null $exceptionHandler = null;
 
     /**
      * @param string             $name       The logging channel, a simple descriptive name that is attached to all log records
@@ -182,7 +178,7 @@ class Logger implements LoggerInterface, ResettableInterface
      */
     public function popHandler(): HandlerInterface
     {
-        if (!$this->handlers) {
+        if (0 === \count($this->handlers)) {
             throw new \LogicException('You tried to pop from an empty handler stack.');
         }
 
@@ -194,7 +190,7 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * If a map is passed, keys will be ignored.
      *
-     * @param HandlerInterface[] $handlers
+     * @param list<HandlerInterface> $handlers
      */
     public function setHandlers(array $handlers): self
     {
@@ -207,7 +203,7 @@ class Logger implements LoggerInterface, ResettableInterface
     }
 
     /**
-     * @return HandlerInterface[]
+     * @return list<HandlerInterface>
      */
     public function getHandlers(): array
     {
@@ -231,7 +227,7 @@ class Logger implements LoggerInterface, ResettableInterface
      */
     public function popProcessor(): callable
     {
-        if (!$this->processors) {
+        if (0 === \count($this->processors)) {
             throw new \LogicException('You tried to pop from an empty processor stack.');
         }
 
@@ -439,14 +435,14 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * The callable will receive an exception object and the record that failed to be logged
      */
-    public function setExceptionHandler(?callable $callback): self
+    public function setExceptionHandler(Closure|null $callback): self
     {
         $this->exceptionHandler = $callback;
 
         return $this;
     }
 
-    public function getExceptionHandler(): ?callable
+    public function getExceptionHandler(): Closure|null
     {
         return $this->exceptionHandler;
     }

+ 7 - 8
src/Monolog/Processor/WebProcessor.php

@@ -11,6 +11,7 @@
 
 namespace Monolog\Processor;
 
+use ArrayAccess;
 use Monolog\LogRecord;
 
 /**
@@ -21,9 +22,9 @@ use Monolog\LogRecord;
 class WebProcessor implements ProcessorInterface
 {
     /**
-     * @var array<string, mixed>|\ArrayAccess<string, mixed>
+     * @var array<string, mixed>|ArrayAccess<string, mixed>
      */
-    protected $serverData;
+    protected array|ArrayAccess $serverData;
 
     /**
      * Default fields
@@ -42,17 +43,15 @@ class WebProcessor implements ProcessorInterface
     ];
 
     /**
-     * @param array<string, mixed>|\ArrayAccess<string, mixed>|null $serverData  Array or object w/ ArrayAccess that provides access to the $_SERVER data
-     * @param array<string, string>|array<string>|null              $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data
+     * @param array<string, mixed>|ArrayAccess<string, mixed>|null $serverData  Array or object w/ ArrayAccess that provides access to the $_SERVER data
+     * @param array<string, string>|array<string>|null             $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data
      */
-    public function __construct($serverData = null, array $extraFields = null)
+    public function __construct(array|ArrayAccess|null $serverData = null, array|null $extraFields = null)
     {
         if (null === $serverData) {
             $this->serverData = &$_SERVER;
-        } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) {
-            $this->serverData = $serverData;
         } else {
-            throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
+            $this->serverData = $serverData;
         }
 
         $defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer'];

+ 1 - 1
tests/Monolog/Formatter/LineFormatterTest.php

@@ -224,7 +224,7 @@ class LineFormatterTest extends TestCase
 
 class TestFoo
 {
-    public $foo = 'fooValue';
+    public string $foo = 'fooValue';
 }
 
 class TestBar

+ 1 - 1
tests/Monolog/Formatter/ScalarFormatterTest.php

@@ -16,7 +16,7 @@ use Monolog\Test\TestCase;
 
 class ScalarFormatterTest extends TestCase
 {
-    private $formatter;
+    private ScalarFormatter $formatter;
 
     public function setUp(): void
     {

+ 1 - 1
tests/Monolog/Handler/BufferHandlerTest.php

@@ -16,7 +16,7 @@ use Monolog\Level;
 
 class BufferHandlerTest extends TestCase
 {
-    private $shutdownCheckHandler;
+    private TestHandler $shutdownCheckHandler;
 
     /**
      * @covers Monolog\Handler\BufferHandler::__construct

+ 1 - 1
tests/Monolog/Handler/ChromePHPHandlerTest.php

@@ -134,7 +134,7 @@ class ChromePHPHandlerTest extends TestCase
 
 class TestChromePHPHandler extends ChromePHPHandler
 {
-    protected $headers = [];
+    protected array $headers = [];
 
     public static function resetStatic(): void
     {

+ 7 - 15
tests/Monolog/Handler/DynamoDbHandlerTest.php

@@ -11,17 +11,19 @@
 
 namespace Monolog\Handler;
 
+use Aws\DynamoDb\DynamoDbClient;
 use Monolog\Test\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
 
 class DynamoDbHandlerTest extends TestCase
 {
-    private $client;
+    private DynamoDbClient&MockObject $client;
 
-    private $isV3;
+    private bool $isV3;
 
     public function setUp(): void
     {
-        if (!class_exists('Aws\DynamoDb\DynamoDbClient')) {
+        if (!class_exists(DynamoDbClient::class)) {
             $this->markTestSkipped('aws/aws-sdk-php not installed');
         }
 
@@ -29,13 +31,13 @@ class DynamoDbHandlerTest extends TestCase
 
         $implementedMethods = ['__call'];
         $absentMethods = [];
-        if (method_exists('Aws\DynamoDb\DynamoDbClient', 'formatAttributes')) {
+        if (method_exists(DynamoDbClient::class, 'formatAttributes')) {
             $implementedMethods[] = 'formatAttributes';
         } else {
             $absentMethods[] = 'formatAttributes';
         }
 
-        $clientMockBuilder = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient')
+        $clientMockBuilder = $this->getMockBuilder(DynamoDbClient::class)
             ->onlyMethods($implementedMethods)
             ->disableOriginalConstructor();
         if ($absentMethods) {
@@ -45,16 +47,6 @@ class DynamoDbHandlerTest extends TestCase
         $this->client = $clientMockBuilder->getMock();
     }
 
-    public function testConstruct()
-    {
-        $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo'));
-    }
-
-    public function testInterface()
-    {
-        $this->assertInstanceOf('Monolog\Handler\HandlerInterface', new DynamoDbHandler($this->client, 'foo'));
-    }
-
     public function testGetFormatter()
     {
         $handler = new DynamoDbHandler($this->client, 'foo');

+ 1 - 1
tests/Monolog/Handler/FirePHPHandlerTest.php

@@ -75,7 +75,7 @@ class FirePHPHandlerTest extends TestCase
 
 class TestFirePHPHandler extends FirePHPHandler
 {
-    protected $headers = [];
+    protected array $headers = [];
 
     public static function resetStatic(): void
     {

+ 3 - 2
tests/Monolog/Handler/HandlerWrapperTest.php

@@ -12,6 +12,7 @@
 namespace Monolog\Handler;
 
 use Monolog\Test\TestCase;
+use PHPUnit\Framework\MockObject\MockObject;
 
 /**
  * @author Alexey Karapetov <alexey@karapetov.com>
@@ -20,12 +21,12 @@ class HandlerWrapperTest extends TestCase
 {
     private HandlerWrapper $wrapper;
 
-    private $handler;
+    private HandlerInterface&MockObject $handler;
 
     public function setUp(): void
     {
         parent::setUp();
-        $this->handler = $this->createMock('Monolog\\Handler\\HandlerInterface');
+        $this->handler = $this->createMock(HandlerInterface::class);
         $this->wrapper = new HandlerWrapper($this->handler);
     }
 

+ 3 - 6
tests/Monolog/Handler/PHPConsoleHandlerTest.php

@@ -28,12 +28,9 @@ use PHPUnit\Framework\MockObject\MockObject;
  */
 class PHPConsoleHandlerTest extends TestCase
 {
-    /** @var  Connector|MockObject */
-    protected $connector;
-    /** @var  DebugDispatcher|MockObject */
-    protected $debugDispatcher;
-    /** @var  ErrorDispatcher|MockObject */
-    protected $errorDispatcher;
+    protected Connector&MockObject $connector;
+    protected DebugDispatcher&MockObject $debugDispatcher;
+    protected ErrorDispatcher&MockObject $errorDispatcher;
 
     protected function setUp(): void
     {

+ 4 - 2
tests/Monolog/Handler/PushoverHandlerTest.php

@@ -13,6 +13,7 @@ namespace Monolog\Handler;
 
 use Monolog\Test\TestCase;
 use Monolog\Level;
+use PHPUnit\Framework\MockObject\MockObject;
 
 /**
  * Almost all examples (expected header, titles, messages) taken from
@@ -22,8 +23,9 @@ use Monolog\Level;
  */
 class PushoverHandlerTest extends TestCase
 {
+    /** @var resource */
     private $res;
-    private $handler;
+    private PushoverHandler&MockObject $handler;
 
     public function testWriteHeader()
     {
@@ -116,7 +118,7 @@ class PushoverHandlerTest extends TestCase
     {
         $constructorArgs = [$token, $user, $title];
         $this->res = fopen('php://memory', 'a');
-        $this->handler = $this->getMockBuilder('Monolog\Handler\PushoverHandler')
+        $this->handler = $this->getMockBuilder(PushoverHandler::class)
             ->setConstructorArgs($constructorArgs)
             ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket'])
             ->getMock();

+ 0 - 7
tests/Monolog/Handler/RedisHandlerTest.php

@@ -17,13 +17,6 @@ use Monolog\Formatter\LineFormatter;
 
 class RedisHandlerTest extends TestCase
 {
-    public function testConstructorShouldThrowExceptionForInvalidRedis()
-    {
-        $this->expectException(\InvalidArgumentException::class);
-
-        new RedisHandler(new \stdClass(), 'key');
-    }
-
     public function testConstructorShouldWorkWithPredis()
     {
         $redis = $this->createMock('Predis\Client');

+ 0 - 7
tests/Monolog/Handler/RedisPubSubHandlerTest.php

@@ -19,13 +19,6 @@ use Monolog\Formatter\LineFormatter;
 
 class RedisPubSubHandlerTest extends TestCase
 {
-    public function testConstructorShouldThrowExceptionForInvalidRedis()
-    {
-        $this->expectException(\InvalidArgumentException::class);
-
-        new RedisPubSubHandler(new \stdClass(), 'key');
-    }
-
     public function testConstructorShouldWorkWithPredis()
     {
         $redis = $this->createMock('Predis\Client');

+ 1 - 1
tests/Monolog/Handler/RotatingFileHandlerTest.php

@@ -19,7 +19,7 @@ use Monolog\Test\TestCase;
  */
 class RotatingFileHandlerTest extends TestCase
 {
-    private $lastError;
+    private array|null $lastError = null;
 
     public function setUp(): void
     {

+ 26 - 27
tests/Monolog/Handler/SocketHandlerTest.php

@@ -20,10 +20,7 @@ use PHPUnit\Framework\MockObject\MockObject;
  */
 class SocketHandlerTest extends TestCase
 {
-    /**
-     * @var \Monolog\Handler\SocketHandler|MockObject
-     */
-    private $handler;
+    private SocketHandler&MockObject $handler;
 
     /**
      * @var resource
@@ -34,58 +31,58 @@ class SocketHandlerTest extends TestCase
     {
         $this->expectException(\UnexpectedValueException::class);
 
-        $this->createHandler('garbage://here');
-        $this->writeRecord('data');
+        $handler = $this->createHandler('garbage://here');
+        $handler->handle($this->getRecord(Level::Warning, 'data'));
     }
 
     public function testBadConnectionTimeout()
     {
         $this->expectException(\InvalidArgumentException::class);
 
-        $this->createHandler('localhost:1234');
-        $this->handler->setConnectionTimeout(-1);
+        $handler = $this->createHandler('localhost:1234');
+        $handler->setConnectionTimeout(-1);
     }
 
     public function testSetConnectionTimeout()
     {
-        $this->createHandler('localhost:1234');
-        $this->handler->setConnectionTimeout(10.1);
-        $this->assertEquals(10.1, $this->handler->getConnectionTimeout());
+        $handler = $this->createHandler('localhost:1234');
+        $handler->setConnectionTimeout(10.1);
+        $this->assertEquals(10.1, $handler->getConnectionTimeout());
     }
 
     public function testBadTimeout()
     {
         $this->expectException(\InvalidArgumentException::class);
 
-        $this->createHandler('localhost:1234');
-        $this->handler->setTimeout(-1);
+        $handler = $this->createHandler('localhost:1234');
+        $handler->setTimeout(-1);
     }
 
     public function testSetTimeout()
     {
-        $this->createHandler('localhost:1234');
-        $this->handler->setTimeout(10.25);
-        $this->assertEquals(10.25, $this->handler->getTimeout());
+        $handler = $this->createHandler('localhost:1234');
+        $handler->setTimeout(10.25);
+        $this->assertEquals(10.25, $handler->getTimeout());
     }
 
     public function testSetWritingTimeout()
     {
-        $this->createHandler('localhost:1234');
-        $this->handler->setWritingTimeout(10.25);
-        $this->assertEquals(10.25, $this->handler->getWritingTimeout());
+        $handler = $this->createHandler('localhost:1234');
+        $handler->setWritingTimeout(10.25);
+        $this->assertEquals(10.25, $handler->getWritingTimeout());
     }
 
     public function testSetChunkSize()
     {
-        $this->createHandler('localhost:1234');
-        $this->handler->setChunkSize(1025);
-        $this->assertEquals(1025, $this->handler->getChunkSize());
+        $handler = $this->createHandler('localhost:1234');
+        $handler->setChunkSize(1025);
+        $this->assertEquals(1025, $handler->getChunkSize());
     }
 
     public function testSetConnectionString()
     {
-        $this->createHandler('tcp://localhost:9090');
-        $this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString());
+        $handler = $this->createHandler('tcp://localhost:9090');
+        $this->assertEquals('tcp://localhost:9090', $handler->getConnectionString());
     }
 
     public function testExceptionIsThrownOnFsockopenError()
@@ -277,10 +274,12 @@ class SocketHandlerTest extends TestCase
         $this->writeRecord('Hello world');
     }
 
-    private function createHandler($connectionString)
+    private function createHandler(string $connectionString): SocketHandler
     {
-        $this->handler = new SocketHandler($connectionString);
-        $this->handler->setFormatter($this->getIdentityFormatter());
+        $handler = new SocketHandler($connectionString);
+        $handler->setFormatter($this->getIdentityFormatter());
+
+        return $handler;
     }
 
     private function writeRecord($string)

+ 0 - 2
tests/Monolog/Handler/ZendMonitorHandlerTest.php

@@ -15,8 +15,6 @@ use Monolog\Test\TestCase;
 
 class ZendMonitorHandlerTest extends TestCase
 {
-    protected $zendMonitorHandler;
-
     public function setUp(): void
     {
         if (!function_exists('zend_monitor_custom_event')) {

+ 1 - 1
tests/Monolog/Processor/WebProcessorTest.php

@@ -118,7 +118,7 @@ class WebProcessorTest extends TestCase
 
     public function testInvalidData()
     {
-        $this->expectException(\UnexpectedValueException::class);
+        $this->expectException(\TypeError::class);
 
         new WebProcessor(new \stdClass);
     }

+ 1 - 1
tests/Monolog/PsrLogCompatTest.php

@@ -24,7 +24,7 @@ use Stringable;
 
 class PsrLogCompatTest extends TestCase
 {
-    private $handler;
+    private TestHandler $handler;
 
     public function getLogger(): LoggerInterface
     {

+ 3 - 3
tests/Monolog/SignalHandlerTest.php

@@ -22,9 +22,9 @@ use Monolog\Test\TestCase;
  */
 class SignalHandlerTest extends TestCase
 {
-    private $asyncSignalHandling;
-    private $blockedSignals;
-    private $signalHandlers;
+    private bool $asyncSignalHandling;
+    private array $blockedSignals = [];
+    private array $signalHandlers = [];
 
     protected function setUp(): void
     {