Setup
Windows, several PHP runtimes side by side. php on PATH is 7.4 because the main project targets 7.4; other repositories on the same machine require PHP 8.3.
1. lint-php cannot use a different PHP than the one running the hook
hooks/lint-php.php lints with PHP_BINARY:
exec(escapeshellarg(PHP_BINARY) . ' -l ' . escapeshellarg($filePath) . ' 2>&1', $output, $exitCode);
hooks.json starts the hook as bare php, so the linting version is whatever php resolves to — one global choice for every project on the machine. Editing a PHP 8 file then reports a syntax error that is not one:
PHP syntax error in .../SchoolInquiryFormConfig.php:
Parse error: syntax error, unexpected 'private' (T_PRIVATE), expecting variable (T_VARIABLE) on line 12
Line 12 is constructor property promotion, in a project whose composer.json says "php": ">=8.3". The check is permanently red, which is worse than no check — a real syntax error looks exactly the same.
.nette-claude.json can only exclude paths, so the only workaround is switching the check off for the whole repository.
Suggestion. The hook already reads a project config; a binary key next to exclude would be enough:
{ "lint-php": { "binary": "C:\php8.4\php.exe" } }
$binary = configValue($filePath, 'lint-php', 'binary') ?? PHP_BINARY;
Deriving it from require.php in the nearest composer.json would work too and need no new configuration.
2. .nette-claude.json fatals when the hooks run on PHP 7.4
hooks/hook-config.php uses PHP 8.0+ functions:
$anchored = str_starts_with($pattern, '/'); // line 89
if (!$anchored && !str_contains($pattern, '/')) { // line 96
The hooks are started with bare php, which is not guaranteed to be PHP 8. With a 7.4 launcher, any .nette-claude.json above the edited file turns every hook that reaches matchesPattern() into:
Fatal error: Uncaught Error: Call to undefined function str_starts_with()
in hooks/hook-config.php:89
So on exactly the setups where the exclusion is needed — an old php on PATH — the exclusion cannot be used. hooks/lint-php.php itself is 7.4-compatible; only the shared config helper is not.
Suggestion. Polyfill the two calls, or document a minimum PHP version for the launcher. The file's own comment says it is duplicated into every plugin, so the fix applies to all of them.
Versions
nette-lint 1.1.0, launcher PHP 7.4.33, Windows.
Setup
Windows, several PHP runtimes side by side.
phpon PATH is 7.4 because the main project targets 7.4; other repositories on the same machine require PHP 8.3.1.
lint-phpcannot use a different PHP than the one running the hookhooks/lint-php.phplints withPHP_BINARY:hooks.jsonstarts the hook as barephp, so the linting version is whateverphpresolves to — one global choice for every project on the machine. Editing a PHP 8 file then reports a syntax error that is not one:Line 12 is constructor property promotion, in a project whose
composer.jsonsays"php": ">=8.3". The check is permanently red, which is worse than no check — a real syntax error looks exactly the same..nette-claude.jsoncan only exclude paths, so the only workaround is switching the check off for the whole repository.Suggestion. The hook already reads a project config; a
binarykey next toexcludewould be enough:{ "lint-php": { "binary": "C:\php8.4\php.exe" } }Deriving it from
require.phpin the nearestcomposer.jsonwould work too and need no new configuration.2.
.nette-claude.jsonfatals when the hooks run on PHP 7.4hooks/hook-config.phpuses PHP 8.0+ functions:The hooks are started with bare
php, which is not guaranteed to be PHP 8. With a 7.4 launcher, any.nette-claude.jsonabove the edited file turns every hook that reachesmatchesPattern()into:So on exactly the setups where the exclusion is needed — an old
phpon PATH — the exclusion cannot be used.hooks/lint-php.phpitself is 7.4-compatible; only the shared config helper is not.Suggestion. Polyfill the two calls, or document a minimum PHP version for the launcher. The file's own comment says it is duplicated into every plugin, so the fix applies to all of them.
Versions
nette-lint 1.1.0, launcher PHP 7.4.33, Windows.