struggle-for-php/sfp-phpstan-psr-log is extra strict and opinionated psr/log (psr-3) rules for PHPStan.
To use this extension, require it in Composer:
composer require --dev struggle-for-php/sfp-phpstan-psr-loginclude extension.neon & rules.neon in your project's PHPStan config:
includes:
- vendor/struggle-for-php/sfp-phpstan-psr-log/rules.neonWrite these parameters to your project's phpstan.neon.
parameters:
sfpPsrLog:
enableMessageStaticStringRule: false # default:true
enableContextRequireExceptionKeyRule: true
reportContextExceptionLogLevel: 'info'
contextKeyOriginalPattern: '#\A[A-Za-z0-9-_]+\z#'This package provides the following rules.
Placeholder names SHOULD be composed only of the characters A-Z, a-z, 0-9, underscore _, and period .
| π error identifier |
|---|
| sfpPsrLog.placeholderCharactersInvalidChar |
- reports when placeholder in
$messagecharacters are not,A-Z,a-z,0-9, underscore_, and period.
// bad
$logger->info('message are {foo-hyphen}');| π error identifier |
|---|
| sfpPsrLog.placeholderCharactersDoubleBraces |
- reports when double braces pair
{{}}are used.
// bad
$logger->info('message are {{foo}}');Placeholder names MUST correspond to keys in the context array.
| π error identifier |
|---|
| sfpPsrLog.placeholderCorrespondToKeysMissedContext |
- reports when placeholder exists in message, but
$contextparameter is missed.
// bad
$logger->info('message has {nonContext} .');| π error identifier |
|---|
| sfpPsrLog.placeholderCorrespondToKeysMissedKey |
- reports when placeholder exists in message, but key in
$contextdoes not exist against them.
// bad
$logger->info('user {user_id} gets an error {error} .', ['user_id' => $user_id]);Note
PSR-3 has no provisions for array keys, but this is useful in many cases.
| π error identifier |
|---|
| sfpPsrLog.contextKeyNonEmptyString |
- reports when context key is not non-empty-string.
// bad
[123 => 'foo']`, `['' => 'bar']`, `['baz']| π error identifier |
|---|
| sfpPsrLog.contextKeyOriginalPattern |
- reports when context key is not matched you defined pattern.
- if
contextKeyOriginalPatternparameter is not set, this check would be ignored.
- if
- You can set specific key pattern by regex.(
preg_match())
parameters:
sfpPsrLog:
contextKeyOriginalPattern: '#\A[A-Za-z0-9-]+\z#'Note
This is not a rule for along with PSR-3 specification, but provides best practices.
| π error identifier |
|---|
| sfpPsrLog.contextRequireExceptionKey |
- It forces
exceptionkey into context parameter when current scope has\Throwableobject.
<?php
/** @var \Psr\Log\LoggerInterface $logger */
try {
//
} catch (LogicException $exception) {
$logger->warning("foo");
}$ ../vendor/bin/phpstan analyse
Note: Using configuration file /tmp/your-project/phpstan.neon.
2/2 [ββββββββββββββββββββββββββββ] 100%
------ -------------------------------------------------------------
Line Demo.php
------ -------------------------------------------------------------
6 Parameter $context of logger method Psr\Log\LoggerInterface::warning() requires \'exception\' key. Current scope has Throwable variable - $exception
------ -------------------------------------------------------------
[ERROR] Found 1 error- You can set the minimum required level to report. (default level is
debug)
parameters:
sfpPsrLog:
reportContextExceptionLogLevel: 'warning'Then, debug| info | notice LogLevel is ignored for report.
} catch (\Exception $e) {
$logger->info('more info'); // allow
$logger->warning($e->getMessage(), ['exception' => $e]);
}- If you want to enable this rule, please add
enableContextRequireExceptionKeyRuleas true.
parameters:
sfpPsrLog:
enableContextRequireExceptionKeyRule: trueNote
This rule validates that the $context parameter has the correct type according to PSR-3 specification.
| π error identifier |
|---|
| sfpPsrLog.contextType |
- reports when
$contextparameter type does not match the expected type.- The default expected type is
array{exception?: Throwable}according to PSR-3.
- The default expected type is
// bad
$logger->info('message', ['exception' => 'string value']); // exception must be Throwable- If you want to disable this rule, please add
enableContextTypeRuleas false.
parameters:
sfpPsrLog:
enableContextTypeRule: falseYou can enforce stricter context types by implementing ContextTypeProviderInterface and injecting it via dependency injection.
- Example: Restricting to specific context keys
<?php
// src/YourCustomContextTypeProvider.php
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayTypeBuilder;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use Sfp\PHPStan\Psr\Log\TypeProvider\ContextTypeProviderInterface;
final class YourCustomContextTypeProvider implements ContextTypeProviderInterface
{
public function getType(): Type
{
$builder = ConstantArrayTypeBuilder::createEmpty();
// Define allowed context keys with their types
$builder->setOffsetValueType(
new ConstantStringType('user_id'),
new StringType(),
true // optional
);
$builder->setOffsetValueType(
new ConstantStringType('exception'),
new ObjectType(\Throwable::class),
true // optional
);
return $builder->getArray();
}
}Configure in phpstan.neon:
services:
yourCustomContextTypeProvider:
class: YourCustomContextTypeProvider
contextTypeProviderResolver:
class: Sfp\PHPStan\Psr\Log\TypeProviderResolver\AnyScopeContextTypeProviderResolver
arguments:
contextTypeProvider: @yourCustomContextTypeProvider
-
class: Sfp\PHPStan\Psr\Log\Rules\ContextTypeRule
arguments:
contextTypeProviderResolver: @contextTypeProviderResolver
tags:
- phpstan.rules.ruleThis allows you to enforce project-specific context types, such as structured logging schemas (e.g., BigQuery) or custom application requirements.
| π error identifier |
|---|
| sfpPsrLog.messageNotStaticString |
- reports when $message is not static string value.
// bad
$logger->info(sprintf('Message contains %s variable', $var));- If you want to disable this rule, please add
enableMessageStaticStringRuleas false.
parameters:
sfpPsrLog:
enableMessageStaticStringRule: falseImplementors MUST implement the following interface, which describes the eight methods to write logs to the eight RFC 5424 levels (debug, info, notice, warning, error, critical, alert, emergency). β PSR-3 Logger Interface
| π error identifier |
|---|
| sfpPsrLog.logMethodLevel |
- reports when the
$levelparameter oflog()method is not a valid PSR-3 log level.- Valid log levels:
emergency,alert,critical,error,warning,notice,info,debug
- Valid log levels:
// bad
$logger->log('panic', 'message'); // 'panic' is not a valid PSR-3 log level
$logger->log(100, 'message'); // level must be a string- If you want to disable this rule, please add
enableLogMethodLevelRuleas false.
parameters:
sfpPsrLog:
enableLogMethodLevelRule: false