Skip to content

str_split returns an empty array since PHP 8.2 #1544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions resources/functionMap_php82delta.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php // phpcs:ignoreFile

/**
* Copied over from https://github.com/phan/phan/blob/8866d6b98be94b37996390da226e8c4befea29aa/src/Phan/Language/Internal/FunctionSignatureMap_php80_delta.php
* Copyright (c) 2015 Rasmus Lerdorf
* Copyright (c) 2015 Andrew Morrison
*/

/**
* This contains the information needed to convert the function signatures for php 8.0 to php 7.4 (and vice versa)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be 8.2 right?

And is this the difference between 7.4 and 8.2, or between 8.1 and 8.2?

Copy link
Contributor Author

@herndlm herndlm Jul 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, see PR description :) UPDATE: and it is the difference between 8.1 and 8.2, yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ondrejmirtes should the delta files all (except the original one where this was copied over) updated in that regard?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't care, I never read that comment :) The filename says it all.

*
* This has two sections.
* The 'new' section contains function/method names from FunctionSignatureMap (And alternates, if applicable) that do not exist in php7.4 or have different signatures in php 8.0.
* If they were just updated, the function/method will be present in the 'added' signatures.
* The 'old' signatures contains the signatures that are different in php 7.4.
* Functions are expected to be removed only in major releases of php.
*
* @see FunctionSignatureMap.php
*
* @phan-file-suppress PhanPluginMixedKeyNoKey (read by Phan when analyzing this file)
*/
return [
'new' => [
'str_split' => ['array<int,string>', 'str'=>'string', 'split_length='=>'positive-int'],
],
'old' => [

]
];
5 changes: 5 additions & 0 deletions src/Php/PhpVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,9 @@ public function deprecatesDynamicProperties(): bool
return $this->versionId >= 80200;
}

public function strSplitReturnsEmptyArray(): bool
{
return $this->versionId >= 80200;
}

}
9 changes: 9 additions & 0 deletions src/Reflection/SignatureMap/FunctionSignatureMapProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ public function getSignatureMap(): array
$signatureMap = $this->computeSignatureMap($signatureMap, $php81MapDelta);
}

if ($this->phpVersion->getVersionId() >= 80200) {
$php82MapDelta = require __DIR__ . '/../../../resources/functionMap_php82delta.php';
if (!is_array($php82MapDelta)) {
throw new ShouldNotHappenException('Signature map could not be loaded.');
}

$signatureMap = $this->computeSignatureMap($signatureMap, $php82MapDelta);
}

$this->signatureMap = $signatureMap;
}

Expand Down
4 changes: 2 additions & 2 deletions src/Type/Php/StrSplitFunctionReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,

$stringType = $scope->getType($functionCall->getArgs()[0]->value);

return TypeTraverser::map($stringType, static function (Type $type, callable $traverse) use ($encoding, $splitLength, $scope): Type {
return TypeTraverser::map($stringType, function (Type $type, callable $traverse) use ($encoding, $splitLength, $scope): Type {
if ($type instanceof UnionType || $type instanceof IntersectionType) {
return $traverse($type);
}

if (!$type instanceof ConstantStringType) {
$returnType = new ArrayType(new IntegerType(), new StringType());

return $encoding === null
return $encoding === null && !$this->phpVersion->strSplitReturnsEmptyArray()
? TypeCombinator::intersect($returnType, new NonEmptyArrayType())
: $returnType;
}
Expand Down
16 changes: 12 additions & 4 deletions tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5138,6 +5138,14 @@ public function testArrayFunctions(

public function dataFunctions(): array
{
$strSplitDefaultReturnType = 'non-empty-array<int, string>|false';
if (PHP_VERSION_ID >= 80000) {
$strSplitDefaultReturnType = 'non-empty-array<int, string>';
}
if (PHP_VERSION_ID >= 80200) {
$strSplitDefaultReturnType = 'array<int, string>';
}

return [
[
'string',
Expand Down Expand Up @@ -5328,15 +5336,15 @@ public function dataFunctions(): array
'$gettimeofdayBenevolent',
],
[
PHP_VERSION_ID < 80000 ? 'non-empty-array<int, string>|false' : 'non-empty-array<int, string>',
$strSplitDefaultReturnType,
'$strSplitConstantStringWithoutDefinedParameters',
],
[
'array{\'a\', \'b\', \'c\', \'d\', \'e\', \'f\'}',
'$strSplitConstantStringWithoutDefinedSplitLength',
],
[
'non-empty-array<int, string>',
PHP_VERSION_ID < 80200 ? 'non-empty-array<int, string>' : 'array<int, string>',
'$strSplitStringWithoutDefinedSplitLength',
],
[
Expand All @@ -5352,15 +5360,15 @@ public function dataFunctions(): array
'$strSplitConstantStringWithFailureSplitLength',
],
[
PHP_VERSION_ID < 80000 ? 'non-empty-array<int, string>|false' : 'non-empty-array<int, string>',
$strSplitDefaultReturnType,
'$strSplitConstantStringWithInvalidSplitLengthType',
],
[
'array{\'a\'|\'g\', \'b\'|\'h\', \'c\'|\'i\', \'d\'|\'j\', \'e\'|\'k\', \'f\'|\'l\'}',
'$strSplitConstantStringWithVariableStringAndConstantSplitLength',
],
[
PHP_VERSION_ID < 80000 ? 'non-empty-array<int, string>|false' : 'non-empty-array<int, string>',
$strSplitDefaultReturnType,
'$strSplitConstantStringWithVariableStringAndVariableSplitLength',
],
// parse_url
Expand Down