From 87f448089a7e10e6bcc765c01f8f556da108c97a Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:00:24 +0200 Subject: [PATCH 01/11] Run tests against PHP 8.5 --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7650042be..8032a535f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,11 +16,11 @@ jobs: coverage: [false] random: [false] include: - - php: '8.2' + - php: '8.4' coverage: true - - php: '8.2' - random: true - php: '8.4' + random: true + - php: '8.5' experimental: true steps: From 621e614b120b3e55cf33232287a916c85964e230 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:03:27 +0200 Subject: [PATCH 02/11] Sync fallback files --- composer.json | 4 ++-- resources/local_fallback/rtv/metadata | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index c7a0ae994..0536e2355 100644 --- a/composer.json +++ b/composer.json @@ -81,8 +81,8 @@ "sync-fallback-files": "bin/sync-amp-runtime-local-fallback-resources.php", "sync-test-specs": "rm -rf tests/spec && bin/sync-amp-toolbox-test-suite.php", "sync": [ - "sync-fallback-files", - "sync-test-specs" + "@sync-fallback-files", + "@sync-test-specs" ] } } diff --git a/resources/local_fallback/rtv/metadata b/resources/local_fallback/rtv/metadata index 737798af2..2f85d338e 100644 --- a/resources/local_fallback/rtv/metadata +++ b/resources/local_fallback/rtv/metadata @@ -1 +1 @@ -{"ampRuntimeVersion":"012502032353000","ampCssUrl":"https://cdn.ampproject.org/rtv/012502032353000/v0.css","canaryPercentage":"0.005","diversions":["002502032353000","022502032353000","032502032353000","042502242315000","052502032353000"],"ltsRuntimeVersion":"012501142147000","ltsCssUrl":"https://cdn.ampproject.org/rtv/012501142147000/v0.css"} \ No newline at end of file +{"ampRuntimeVersion":"012508201830000","ampCssUrl":"https://cdn.ampproject.org/rtv/012508201830000/v0.css","canaryPercentage":"0.005","diversions":["002508281901000","022508201830000","032508281901000","042509031727000","052508201830000"],"ltsRuntimeVersion":"012508201830000","ltsCssUrl":"https://cdn.ampproject.org/rtv/012508201830000/v0.css"} \ No newline at end of file From c525081c34abc7b8ac20f7283660a9bf14043107 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:09:51 +0200 Subject: [PATCH 03/11] Update `actions/cache` to v4 --- .github/workflows/sync-local-fallback-files.yml | 2 +- .github/workflows/sync-spec-test-suite.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sync-local-fallback-files.yml b/.github/workflows/sync-local-fallback-files.yml index e573531ec..45989eef8 100644 --- a/.github/workflows/sync-local-fallback-files.yml +++ b/.github/workflows/sync-local-fallback-files.yml @@ -26,7 +26,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Configure Composer cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/sync-spec-test-suite.yml b/.github/workflows/sync-spec-test-suite.yml index 7c867a673..346be2352 100644 --- a/.github/workflows/sync-spec-test-suite.yml +++ b/.github/workflows/sync-spec-test-suite.yml @@ -26,7 +26,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Configure Composer cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8032a535f..c0dd35985 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,7 +41,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Configure Composer cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -98,7 +98,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Configure Composer cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -137,7 +137,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Configure Composer cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} From b468476abc847be1e00bc077d5c74feebd1ec356 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:10:42 +0200 Subject: [PATCH 04/11] Add Dependabot config for GitHub Actions --- .github/dependabot.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5d9b87100..877f6f422 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,9 +1,18 @@ version: 2 updates: - package-ecosystem: composer - directory: "/" + directory: '/' schedule: - interval: daily - time: "12:00" - timezone: America/Los_Angeles + interval: monthly open-pull-requests-limit: 10 +- package-ecosystem: github-actions + directory: '/' + schedule: + interval: monthly + open-pull-requests-limit: 10 + labels: + - Dependencies + groups: + github-actions: + patterns: + - '*' From 27476f9f98fade1132d48b53be4c2f00e39d352e Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:31:39 +0200 Subject: [PATCH 05/11] Make data provider static --- tests/Optimizer/SpecTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Optimizer/SpecTest.php b/tests/Optimizer/SpecTest.php index 67b93071b..22c14a96e 100644 --- a/tests/Optimizer/SpecTest.php +++ b/tests/Optimizer/SpecTest.php @@ -66,7 +66,7 @@ final class SpecTest extends TestCase * * @return array Scenarios to test. */ - public function dataTransformerSpecFiles() + public static function dataTransformerSpecFiles() { $scenarios = []; $suites = [ From d0ce47385e493075d6532ee7f920a9c08a23b5f1 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:32:07 +0200 Subject: [PATCH 06/11] Update test fixture files --- .../RewriteAmpUrls/adds_lts_ampjs/expected_output.html | 10 ++++------ .../adds_preloads_ampjs/expected_output.html | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html b/tests/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html index aa570f4cf..9bacd36ca 100644 --- a/tests/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html +++ b/tests/spec/transformers/valid/RewriteAmpUrls/adds_lts_ampjs/expected_output.html @@ -1,13 +1,11 @@ - - - + + + - - - \ No newline at end of file + diff --git a/tests/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html b/tests/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html index 4a160fd16..9bacd36ca 100644 --- a/tests/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html +++ b/tests/spec/transformers/valid/RewriteAmpUrls/adds_preloads_ampjs/expected_output.html @@ -1,13 +1,11 @@ - - - + + + - - - \ No newline at end of file + From 06154da6092708ac3b69ef15de4a5e9592033bca Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:34:04 +0200 Subject: [PATCH 07/11] Fix some deprecations --- src/RemoteRequest/CurlRemoteGetRequest.php | 4 +++- tests/Optimizer/SpecTest.php | 4 +++- tests/Optimizer/TransformationEngineTest.php | 4 +++- tests/src/PrivateAccess.php | 12 +++++++++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/RemoteRequest/CurlRemoteGetRequest.php b/src/RemoteRequest/CurlRemoteGetRequest.php index 18fff0961..21d59d66c 100644 --- a/src/RemoteRequest/CurlRemoteGetRequest.php +++ b/src/RemoteRequest/CurlRemoteGetRequest.php @@ -136,7 +136,9 @@ static function ($curl, $header) use (&$headers) { $status = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE); $curlErrno = curl_errno($curlHandle); - curl_close($curlHandle); + if ( PHP_VERSION_ID < 80000 ) { + curl_close($curlHandle); + } if ($body === false || $status < 200 || $status >= 300) { if (! $retriesLeft || in_array($curlErrno, self::RETRYABLE_ERROR_CODES, true) === false) { diff --git a/tests/Optimizer/SpecTest.php b/tests/Optimizer/SpecTest.php index 22c14a96e..a522046cc 100644 --- a/tests/Optimizer/SpecTest.php +++ b/tests/Optimizer/SpecTest.php @@ -340,7 +340,9 @@ private function getTransformer($scenario, $transformerClass, $configuration) private function callPrivateMethod($object, $methodName, $args = []) { $method = (new ReflectionClass($object))->getMethod($methodName); - $method->setAccessible(true); + if ( PHP_VERSION_ID < 80100 ) { + $method->setAccessible(true); + } return $method->invokeArgs($object, $args); } diff --git a/tests/Optimizer/TransformationEngineTest.php b/tests/Optimizer/TransformationEngineTest.php index a0d2237d6..31a7155cb 100644 --- a/tests/Optimizer/TransformationEngineTest.php +++ b/tests/Optimizer/TransformationEngineTest.php @@ -151,7 +151,9 @@ private function getTransformationEngine(?Configuration $configuration = null) private function getPrivateProperty($object, $propertyName) { $property = ( new ReflectionClass($object) )->getProperty($propertyName); - $property->setAccessible(true); + if ( PHP_VERSION_ID < 80100 ) { + $property->setAccessible(true); + } return $property->getValue($object); } } diff --git a/tests/src/PrivateAccess.php b/tests/src/PrivateAccess.php index 064e288c8..37f474243 100644 --- a/tests/src/PrivateAccess.php +++ b/tests/src/PrivateAccess.php @@ -26,7 +26,9 @@ trait PrivateAccess private function callPrivateMethod($object, $methodName, $args = []) { $method = ( new ReflectionClass($object) )->getMethod($methodName); - $method->setAccessible(true); + if ( PHP_VERSION_ID < 80100 ) { + $method->setAccessible(true); + } return $method->invokeArgs($object, $args); } @@ -57,7 +59,9 @@ private function callPrivateStaticMethod($class, $methodName, $args = []) private function setPrivateProperty($object, $propertyName, $value) { $property = ( new ReflectionClass($object) )->getProperty($propertyName); - $property->setAccessible(true); + if ( PHP_VERSION_ID < 80100 ) { + $property->setAccessible(true); + } // Note: In PHP 8, `ReflectionProperty::getValue()` now requires that an object be supplied if it's a // non-static property. @@ -75,7 +79,9 @@ private function setPrivateProperty($object, $propertyName, $value) private function getPrivateProperty($object, $propertyName) { $property = ( new ReflectionClass($object) )->getProperty($propertyName); - $property->setAccessible(true); + if ( PHP_VERSION_ID < 80100 ) { + $property->setAccessible(true); + } // Note: In PHP 8, `ReflectionProperty::getValue()` now requires that an object be supplied if it's a // non-static property. From 28ec869c737958e4af3313e58fc0b1f69df3ac28 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:36:12 +0200 Subject: [PATCH 08/11] Remove whitespace --- src/RemoteRequest/CurlRemoteGetRequest.php | 2 +- tests/Optimizer/SpecTest.php | 2 +- tests/Optimizer/TransformationEngineTest.php | 2 +- tests/src/PrivateAccess.php | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/RemoteRequest/CurlRemoteGetRequest.php b/src/RemoteRequest/CurlRemoteGetRequest.php index 21d59d66c..174c4f15a 100644 --- a/src/RemoteRequest/CurlRemoteGetRequest.php +++ b/src/RemoteRequest/CurlRemoteGetRequest.php @@ -136,7 +136,7 @@ static function ($curl, $header) use (&$headers) { $status = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE); $curlErrno = curl_errno($curlHandle); - if ( PHP_VERSION_ID < 80000 ) { + if (PHP_VERSION_ID < 80000) { curl_close($curlHandle); } diff --git a/tests/Optimizer/SpecTest.php b/tests/Optimizer/SpecTest.php index a522046cc..49c640d57 100644 --- a/tests/Optimizer/SpecTest.php +++ b/tests/Optimizer/SpecTest.php @@ -340,7 +340,7 @@ private function getTransformer($scenario, $transformerClass, $configuration) private function callPrivateMethod($object, $methodName, $args = []) { $method = (new ReflectionClass($object))->getMethod($methodName); - if ( PHP_VERSION_ID < 80100 ) { + if (PHP_VERSION_ID < 80100) { $method->setAccessible(true); } diff --git a/tests/Optimizer/TransformationEngineTest.php b/tests/Optimizer/TransformationEngineTest.php index 31a7155cb..57f7e6d2f 100644 --- a/tests/Optimizer/TransformationEngineTest.php +++ b/tests/Optimizer/TransformationEngineTest.php @@ -151,7 +151,7 @@ private function getTransformationEngine(?Configuration $configuration = null) private function getPrivateProperty($object, $propertyName) { $property = ( new ReflectionClass($object) )->getProperty($propertyName); - if ( PHP_VERSION_ID < 80100 ) { + if (PHP_VERSION_ID < 80100) { $property->setAccessible(true); } return $property->getValue($object); diff --git a/tests/src/PrivateAccess.php b/tests/src/PrivateAccess.php index 37f474243..06ee4ef04 100644 --- a/tests/src/PrivateAccess.php +++ b/tests/src/PrivateAccess.php @@ -26,7 +26,7 @@ trait PrivateAccess private function callPrivateMethod($object, $methodName, $args = []) { $method = ( new ReflectionClass($object) )->getMethod($methodName); - if ( PHP_VERSION_ID < 80100 ) { + if (PHP_VERSION_ID < 80100) { $method->setAccessible(true); } return $method->invokeArgs($object, $args); @@ -59,7 +59,7 @@ private function callPrivateStaticMethod($class, $methodName, $args = []) private function setPrivateProperty($object, $propertyName, $value) { $property = ( new ReflectionClass($object) )->getProperty($propertyName); - if ( PHP_VERSION_ID < 80100 ) { + if (PHP_VERSION_ID < 80100) { $property->setAccessible(true); } @@ -79,7 +79,7 @@ private function setPrivateProperty($object, $propertyName, $value) private function getPrivateProperty($object, $propertyName) { $property = ( new ReflectionClass($object) )->getProperty($propertyName); - if ( PHP_VERSION_ID < 80100 ) { + if (PHP_VERSION_ID < 80100) { $property->setAccessible(true); } From 537e7888b5665a32653df7dc53458dd19da4a8fe Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:51:00 +0200 Subject: [PATCH 09/11] Address phpstan errors --- phpstan.neon.dist | 5 +- src/Cli/AmpExecutable.php | 1 + src/Cli/Options.php | 2 - src/CssLength.php | 2 +- src/Dom/Document.php | 57 ++----------------- .../Filter/MustacheScriptTemplates.php | 1 + src/Dom/Element.php | 6 +- src/Html/Parser/ParsedTag.php | 7 --- src/Optimizer/ImageDimensions.php | 4 +- src/Optimizer/TransformationEngine.php | 14 ++--- .../Transformer/OptimizeViewport.php | 1 + .../TemporaryFileCachedRemoteGetRequest.php | 7 +-- src/Validator/ValidationErrorCollection.php | 7 --- src/Validator/ValidationSeverity.php | 1 + src/Validator/ValidationStatus.php | 1 + 15 files changed, 23 insertions(+), 93 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 2169f75cf..f195fa9f8 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -4,15 +4,13 @@ includes: parameters: level: 5 inferPrivatePropertyTypeFromConstructor: true + treatPhpDocTypesAsCertain: false paths: - include/ - src/ ignoreErrors: - '#^PHPDoc tag @throws with type AmpProject\\Exception\\FailedRemoteRequest is not subtype of Throwable$#' - '#^Parameter \#1 (\$exception_handler|\$callback) of function set_exception_handler expects#' - - # @see https://github.com/phpstan/phpstan/issues/5655 - - '#^PHPDoc tag @var for constant (?:.*) with type array(?:.*) is not subtype of value array(?:.*)\.$#' excludePaths: analyse: - src/FakeEnum.php @@ -22,3 +20,4 @@ parameters: - src/Validator/ValidationErrorCollection.php - src/Validator/ValidationHandler.php - src/Validator/ValidatorRules.php + - src/Validator/Spec diff --git a/src/Cli/AmpExecutable.php b/src/Cli/AmpExecutable.php index 4838832a3..7c11e73b3 100644 --- a/src/Cli/AmpExecutable.php +++ b/src/Cli/AmpExecutable.php @@ -38,6 +38,7 @@ protected function setup(Options $options) { foreach (self::COMMAND_CLASSES as $commandClass) { /** @var Command $command */ + // @phpstan-ignore varTag.nativeType $command = new $commandClass($this); $command->register($options); diff --git a/src/Cli/Options.php b/src/Cli/Options.php index 8b7821119..ff5a234be 100644 --- a/src/Cli/Options.php +++ b/src/Cli/Options.php @@ -542,8 +542,6 @@ private function readPHPArgv() } if ( - is_array($_SERVER) - && array_key_exists('argv', $_SERVER) && is_array($_SERVER['argv']) diff --git a/src/CssLength.php b/src/CssLength.php index 0af3fe269..a5b92b3ba 100644 --- a/src/CssLength.php +++ b/src/CssLength.php @@ -111,7 +111,7 @@ public function validate($allowAuto, $allowFluid) $pattern = '/^(?\d+(?:\.\d+)?)(?px|em|rem|vh|vw|vmin|vmax)?$/'; if (preg_match($pattern, $this->attrValue, $match)) { $this->isValid = true; - $this->numeral = isset($match['numeral']) ? (float)$match['numeral'] : $this->numeral; + $this->numeral = (float)$match['numeral']; $this->unit = $match['unit'] ?? $this->unit; } } diff --git a/src/Dom/Document.php b/src/Dom/Document.php index f9a7a6a38..b7e84338f 100644 --- a/src/Dom/Document.php +++ b/src/Dom/Document.php @@ -434,11 +434,7 @@ public function saveHTMLFragment(?DOMNode $node = null) } } - if (null === $node || PHP_VERSION_ID >= 70300) { - $html = parent::saveHTML($node); - } else { - $html = $this->extractNodeViaFragmentBoundaries($node); - } + $html = parent::saveHTML($node); foreach ($filtersInReverse as $filter) { if ($filter instanceof AfterSaveFilter) { @@ -474,43 +470,6 @@ private function insertMissingCharset() $this->head->insertBefore($charset, $this->head->firstChild); } - /** - * Extract a node's HTML via fragment boundaries. - * - * Temporarily adds fragment boundary comments in order to locate the desired node to extract from - * the given HTML document. This is required because libxml seems to only preserve whitespace when - * serializing when calling DOMDocument::saveHTML() on the entire document. If you pass the element - * to DOMDocument::saveHTML() then formatting whitespace gets added unexpectedly. This is seen to - * be fixed in PHP 7.3, but for older versions of PHP the following workaround is needed. - * - * @param DOMNode $node Node to extract the HTML for. - * @return string Extracted HTML string. - */ - private function extractNodeViaFragmentBoundaries(DOMNode $node) - { - $boundary = $this->uniqueIdManager->getUniqueId('fragment_boundary'); - $startBoundary = $boundary . ':start'; - $endBoundary = $boundary . ':end'; - $commentStart = $this->createComment($startBoundary); - $commentEnd = $this->createComment($endBoundary); - - $node->parentNode->insertBefore($commentStart, $node); - $node->parentNode->insertBefore($commentEnd, $node->nextSibling); - - $pattern = '/^.*?' - . preg_quote("", '/') - . '(.*)' - . preg_quote("", '/') - . '.*?\s*$/s'; - - $html = preg_replace($pattern, '$1', parent::saveHTML()); - - $node->parentNode->removeChild($commentStart); - $node->parentNode->removeChild($commentEnd); - - return $html; - } - /** * Normalize the document structure. * @@ -1144,16 +1103,10 @@ private function instantiateFilter($filterClass) foreach ($parameters as $parameter) { $dependencyType = null; - // The use of `ReflectionParameter::getClass()` is deprecated in PHP 8, and is superseded - // by `ReflectionParameter::getType()`. See https://github.com/php/php-src/pull/5209. - if (PHP_VERSION_ID >= 70100) { - if ($parameter->getType()) { - /** @var ReflectionNamedType $returnType */ - $returnType = $parameter->getType(); - $dependencyType = new ReflectionClass($returnType->getName()); - } - } else { - $dependencyType = $parameter->getClass(); + if ($parameter->getType()) { + /** @var ReflectionNamedType $returnType */ + $returnType = $parameter->getType(); + $dependencyType = new ReflectionClass($returnType->getName()); } if ($dependencyType === null) { diff --git a/src/Dom/Document/Filter/MustacheScriptTemplates.php b/src/Dom/Document/Filter/MustacheScriptTemplates.php index 1bc6f18e0..b257c0741 100644 --- a/src/Dom/Document/Filter/MustacheScriptTemplates.php +++ b/src/Dom/Document/Filter/MustacheScriptTemplates.php @@ -127,6 +127,7 @@ static function ($matches) use ($mustacheTagPlaceholders) { // entities. In the case of a URL value like '/foo/?bar=1&baz=2' the result is a warning for an // unterminated entity reference "baz". When the attribute value is updated via setAttribute() this // same problem does not occur, so that is why the following is used. + // @phpstan-ignore method.notFound $attribute->parentNode->setAttribute($attribute->nodeName, $value); $this->mustacheTagsReplaced = true; diff --git a/src/Dom/Element.php b/src/Dom/Element.php index 28d6d93b3..78336853f 100644 --- a/src/Dom/Element.php +++ b/src/Dom/Element.php @@ -77,7 +77,7 @@ public function addInlineStyle($style, $prepend = false) * @return DOMAttr|false The new or modified DOMAttr or false if an error occurred. * @throws MaxCssByteCountExceeded If the allowed max byte count is exceeded. */ - public function setAttribute($name, $value) + public function setAttribute($name, $value) // @phpstan-ignore return.unusedType { // Make sure $value is always a string and not null. $value = strval($value); @@ -191,7 +191,7 @@ public static function mergeAmpActions($first, $second) $matches = []; $results = preg_match_all(self::AMP_EVENT_ACTIONS_REGEX_PATTERN, $eventActionString, $matches); - if (! $results || ! isset($matches['event'])) { + if (! $results) { continue; } @@ -209,7 +209,7 @@ static function ($actions) use (&$actionsArray) { $matches = []; $results = preg_match_all(self::AMP_ACTION_REGEX_PATTERN, $actions, $matches); - if (! $results || ! isset($matches['action'])) { + if (! $results) { $actionsArray[] = $actions; return; } diff --git a/src/Html/Parser/ParsedTag.php b/src/Html/Parser/ParsedTag.php index 6311fbc17..35802b913 100644 --- a/src/Html/Parser/ParsedTag.php +++ b/src/Html/Parser/ParsedTag.php @@ -77,13 +77,6 @@ public function __construct($tagName, $alternatingAttributes = []) // Sort the attribute array by (lower case) name. usort($this->attributes, function (ParsedAttribute $a, ParsedAttribute $b) { - if (PHP_MAJOR_VERSION < 7 && $a->name() === $b->name()) { - // Hack required for PHP 5.6, as it does not maintain stable order for equal items. - // See https://bugs.php.net/bug.php?id=69158. - // To get around this, we compare the index within $this->attributes instead to maintain existing order. - return strcmp(array_search($a, $this->attributes, true), array_search($b, $this->attributes, true)); - } - return strcmp($a->name(), $b->name()); }); diff --git a/src/Optimizer/ImageDimensions.php b/src/Optimizer/ImageDimensions.php index b4cc4d7aa..6db77bf21 100644 --- a/src/Optimizer/ImageDimensions.php +++ b/src/Optimizer/ImageDimensions.php @@ -47,14 +47,14 @@ final class ImageDimensions /** * Unit of the width of the image. * - * @var int|float|string|null + * @var string|null */ private $widthUnit; /** * Unit of the height of the image. * - * @var int|float|string|null + * @var string|null */ private $heightUnit; diff --git a/src/Optimizer/TransformationEngine.php b/src/Optimizer/TransformationEngine.php index 192470a86..d827994dc 100644 --- a/src/Optimizer/TransformationEngine.php +++ b/src/Optimizer/TransformationEngine.php @@ -127,16 +127,10 @@ private function getTransformerDependencies($transformerClass) foreach ($constructor->getParameters() as $parameter) { $dependencyType = null; - // The use of `ReflectionParameter::getClass()` is deprecated in PHP 8, and is superseded - // by `ReflectionParameter::getType()`. See https://github.com/php/php-src/pull/5209. - if (PHP_VERSION_ID >= 70100) { - if ($parameter->getType()) { - /** @var \ReflectionNamedType $returnType */ - $returnType = $parameter->getType(); - $dependencyType = new ReflectionClass($returnType->getName()); - } - } else { - $dependencyType = $parameter->getClass(); + if ($parameter->getType()) { + /** @var \ReflectionNamedType $returnType */ + $returnType = $parameter->getType(); + $dependencyType = new ReflectionClass($returnType->getName()); } if ($dependencyType === null) { diff --git a/src/Optimizer/Transformer/OptimizeViewport.php b/src/Optimizer/Transformer/OptimizeViewport.php index 0a787a0d5..ab7d93434 100644 --- a/src/Optimizer/Transformer/OptimizeViewport.php +++ b/src/Optimizer/Transformer/OptimizeViewport.php @@ -82,6 +82,7 @@ public function transform(Document $document, ErrorCollection $errors) // Merge one or more meta[name=viewport] tags into one. $parsedRules = []; + /** @var \DOMElement $metaTag */ foreach ($metaTags as $metaTag) { $propertyPairs = explode(',', $metaTag->getAttribute('content')); diff --git a/src/RemoteRequest/TemporaryFileCachedRemoteGetRequest.php b/src/RemoteRequest/TemporaryFileCachedRemoteGetRequest.php index 55ffa4a5e..bf534f560 100644 --- a/src/RemoteRequest/TemporaryFileCachedRemoteGetRequest.php +++ b/src/RemoteRequest/TemporaryFileCachedRemoteGetRequest.php @@ -86,12 +86,7 @@ public function get($url, $headers = []) // phpcs:disable PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound if ($cachedResponse !== false) { - if (PHP_MAJOR_VERSION >= 7) { - $cachedResponse = unserialize($cachedResponse, [RemoteGetRequestResponse::class]); - } else { - // PHP 5.6 does not provide the second $options argument yet. - $cachedResponse = unserialize($cachedResponse); - } + $cachedResponse = unserialize($cachedResponse, [RemoteGetRequestResponse::class]); } // phpcs:enable PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound diff --git a/src/Validator/ValidationErrorCollection.php b/src/Validator/ValidationErrorCollection.php index 33bbf7d08..80d6e6667 100644 --- a/src/Validator/ValidationErrorCollection.php +++ b/src/Validator/ValidationErrorCollection.php @@ -67,13 +67,6 @@ public function sortByPosition() $this->errors, function (ValidationError $a, ValidationError $b) { if ($a->getLine() === $b->getLine()) { - if (PHP_MAJOR_VERSION < 7 && $a->getColumn() === $b->getColumn()) { - // Hack required for PHP 5.6, as it does not maintain stable order for equal items. - // See https://bugs.php.net/bug.php?id=69158. - // To get around this, we compare the index within $this->errors instead to keep existing order. - return strcmp(array_search($a, $this->errors, true), array_search($b, $this->errors, true)); - } - return $a->getColumn() - $b->getColumn(); } diff --git a/src/Validator/ValidationSeverity.php b/src/Validator/ValidationSeverity.php index c67f880f0..82ccdbafb 100644 --- a/src/Validator/ValidationSeverity.php +++ b/src/Validator/ValidationSeverity.php @@ -50,6 +50,7 @@ public function asString() */ public function __toString() { + // @phpstan-ignore possiblyImpure.methodCall return $this->asString(); } } diff --git a/src/Validator/ValidationStatus.php b/src/Validator/ValidationStatus.php index fece18c48..e2ef48054 100644 --- a/src/Validator/ValidationStatus.php +++ b/src/Validator/ValidationStatus.php @@ -46,6 +46,7 @@ public function asString() */ public function __toString() { + // @phpstan-ignore possiblyImpure.methodCall return $this->asString(); } } From 50868d5b8c2d9cc620d17d1e25d56468f3b48054 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:51:05 +0200 Subject: [PATCH 10/11] Composer update --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0536e2355..9e2ee5da4 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ }, "require-dev": { "ext-zip": "*", - "civicrm/composer-downloads-plugin": "^2.1 || ^3.0", + "civicrm/composer-downloads-plugin": "^4.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1 || ^1.0.0", "mikey179/vfsstream": "^1.6", "php-parallel-lint/php-parallel-lint": "^1.2", @@ -22,7 +22,7 @@ "roave/security-advisories": "dev-master", "sirbrillig/phpcs-variable-analysis": "^2.11.2", "squizlabs/php_codesniffer": "^3", - "wp-coding-standards/wpcs": "^2.3", + "wp-coding-standards/wpcs": "^3.2", "yoast/phpunit-polyfills": "^0.2.0 || ^1.0.0" }, "suggest": { From 098b4d473d33723aae7b3e229f9ae2d806b61043 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 9 Sep 2025 15:53:51 +0200 Subject: [PATCH 11/11] Lint fix --- src/Dom/Document/Filter/MustacheScriptTemplates.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Dom/Document/Filter/MustacheScriptTemplates.php b/src/Dom/Document/Filter/MustacheScriptTemplates.php index b257c0741..800c403aa 100644 --- a/src/Dom/Document/Filter/MustacheScriptTemplates.php +++ b/src/Dom/Document/Filter/MustacheScriptTemplates.php @@ -127,6 +127,7 @@ static function ($matches) use ($mustacheTagPlaceholders) { // entities. In the case of a URL value like '/foo/?bar=1&baz=2' the result is a warning for an // unterminated entity reference "baz". When the attribute value is updated via setAttribute() this // same problem does not occur, so that is why the following is used. + // @phpstan-ignore method.notFound $attribute->parentNode->setAttribute($attribute->nodeName, $value);