Skip to content
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

Symfony 4.4.27 upgrade falls over on PHP 7.4 when calling str_contains #42280

Closed
crmpicco opened this issue Jul 27, 2021 · 34 comments · Fixed by #42296
Closed

Symfony 4.4.27 upgrade falls over on PHP 7.4 when calling str_contains #42280

crmpicco opened this issue Jul 27, 2021 · 34 comments · Fixed by #42296

Comments

@crmpicco
Copy link

Symfony version(s) affected: 4.4.27

Description
I have just upgraded from Symfony 4.4.26 to 4.4.27 and have hit my first upgrade issue in a long time.

I am running PHP 7.4.15 as i'm not ready for PHP 8 yet, however the Yaml Parser.php is looking for str_contains - which is only available in PHP 8.

PHP Fatal error: Uncaught Error: Call to undefined function

Symfony\Component\Yaml\str_contains() in

/private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php:214

I was under the impression the polyfills existed for this reason, but they don't seem to be working this time.

How to reproduce
composer update

Additional context
I was under the impression the polyfills existed for this reason, but they don't seem to be working this time.

Bizarrely the app still boots up, but a composer update falls over as per output below:

composer update     
Loading composer repositories with package information
Updating dependencies                                 
Lock file operations: 0 installs, 10 updates, 0 removals
  - Upgrading aws/aws-sdk-php (3.185.3 => 3.185.21)
  - Upgrading doctrine/cache (2.0.3 => 2.1.1)
  - Upgrading doctrine/migrations (3.1.4 => 3.2.0)
  - Upgrading laminas/laminas-code (4.4.0 => 4.4.2)
  - Upgrading nikic/php-parser (v4.10.5 => v4.12.0)
  - Upgrading phar-io/manifest (2.0.1 => 2.0.3)
  - Upgrading phpunit/phpunit (9.5.6 => 9.5.7)
  - Upgrading symfony/maker-bundle (v1.32.0 => v1.33.0)
  - Upgrading symfony/symfony (v4.4.26 => v4.4.27)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 10 updates, 0 removals
  - Downloading aws/aws-sdk-php (3.185.21)
  - Downloading symfony/symfony (v4.4.27)
  - Downloading laminas/laminas-code (4.4.2)
  - Downloading doctrine/cache (2.1.1)
  - Downloading doctrine/migrations (3.2.0)
  - Downloading nikic/php-parser (v4.12.0)
  - Downloading phar-io/manifest (2.0.3)
  - Downloading phpunit/phpunit (9.5.7)
  - Downloading symfony/maker-bundle (v1.33.0)
  - Upgrading aws/aws-sdk-php (3.185.3 => 3.185.21): Extracting archive
  - Upgrading symfony/symfony (v4.4.26 => v4.4.27): Extracting archive
  - Upgrading laminas/laminas-code (4.4.0 => 4.4.2): Extracting archive
  - Upgrading doctrine/cache (2.0.3 => 2.1.1): Extracting archive
  - Upgrading doctrine/migrations (3.1.4 => 3.2.0): Extracting archive
  - Upgrading nikic/php-parser (v4.10.5 => v4.12.0): Extracting archive
  - Upgrading phar-io/manifest (2.0.1 => 2.0.3): Extracting archive
  - Upgrading phpunit/phpunit (9.5.6 => 9.5.7): Extracting archive
  - Upgrading symfony/maker-bundle (v1.32.0 => v1.33.0): Extracting archive
Package mandrill/mandrill is abandoned, you should avoid using it. Use mailchimp/transactional instead.
Package sebastian/resource-operations is abandoned, you should avoid using it. No replacement was suggested.
Generating autoload files
composer/package-versions-deprecated: Generating version class...
composer/package-versions-deprecated: ...done generating version class
60 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> Incenteev\ParameterHandler\ScriptHandler::buildParameters
Updating the "app/config/parameters.yml" file
PHP Fatal error:  Uncaught Error: Call to undefined function Symfony\Component\Yaml\str_contains() in /private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php:214
Stack trace:
#0 /private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php(96): Symfony\Component\Yaml\Parser->doParse('parameters:\n   ...', 0)
#1 /private/var/www/crmpicco/vendor/incenteev/composer-parameter-handler/Processor.php(34): Symfony\Component\Yaml\Parser->parse('# This file is ...')
#2 /private/var/www/crmpicco/vendor/incenteev/composer-parameter-handler/ScriptHandler.php(34): Incenteev\ParameterHandler\Processor->processFile(Array)
#3 phar:///usr/local/Cellar/composer/1.9.2/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php(377): Incenteev\ParameterHandler\ScriptHandler::buildParameters(Object(Composer\Script\Event))
#4 phar:///usr/local/Cellar/composer/1.9.2/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php(236): Composer\EventDispatcher\EventDispatcher->execute in /private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php on line 214

Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Yaml\str_contains() in /private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php:214
Stack trace:
#0 /private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php(96): Symfony\Component\Yaml\Parser->doParse('parameters:\n   ...', 0)
#1 /private/var/www/crmpicco/vendor/incenteev/composer-parameter-handler/Processor.php(34): Symfony\Component\Yaml\Parser->parse('# This file is ...')
#2 /private/var/www/crmpicco/vendor/incenteev/composer-parameter-handler/ScriptHandler.php(34): Incenteev\ParameterHandler\Processor->processFile(Array)
#3 phar:///usr/local/Cellar/composer/1.9.2/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php(377): Incenteev\ParameterHandler\ScriptHandler::buildParameters(Object(Composer\Script\Event))
#4 phar:///usr/local/Cellar/composer/1.9.2/bin/composer/src/Composer/EventDispatcher/EventDispatcher.php(236): Composer\EventDispatcher\EventDispatcher->execute in /private/var/www/crmpicco/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php on line 214

The polyfills are all installed:

composer show | grep polyfill

paragonie/random_compat              v9.99.100          PHP 5.x polyfill for random_bytes() and random_int() from PHP 7
ralouphie/getallheaders              3.0.3              A polyfill for getallheaders.
symfony/polyfill-ctype               v1.23.0            Symfony polyfill for ctype functions
symfony/polyfill-iconv               v1.23.0            Symfony polyfill for the Iconv extension
symfony/polyfill-intl-icu            v1.23.0            Symfony polyfill for intl's ICU-related data and classes
symfony/polyfill-intl-idn            v1.23.0            Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions
symfony/polyfill-intl-normalizer     v1.23.0            Symfony polyfill for intl's Normalizer class and related functions
symfony/polyfill-mbstring            v1.23.0            Symfony polyfill for the Mbstring extension
symfony/polyfill-php72               v1.23.0            Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions
symfony/polyfill-php73               v1.23.0            Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions
symfony/polyfill-php80               v1.23.0            Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
symfony/polyfill-php81               v1.23.0            Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions

Removing the following from my composer.json fixes it, but i'm not convinced I can safely remove that and leave it out:

        "post-update-cmd": [
            "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters"
        ]
@pduersteler
Copy link

pduersteler commented Jul 27, 2021

I just saw this issue because I experience the same error, but in a different version; For me, this happens after updating from 5.3.x to 5.3.4 on php7.4. The error is thrown in the Dotenv class, though;

Call to undefined function Symfony\Component\Dotenv\str_contains() in /Users/foo/vendor/symfony/dotenv/Dotenv.php:484

Composer version 2.0.8 2020-12-03 17:20:38

@derrabus
Copy link
Member

@crmpicco What version of Composer are you using?

@dmaicher
Copy link
Contributor

For me the same happens using

$ composer --version
Composer version 2.1.5 2021-07-23 10:35:47

@derrabus
Copy link
Member

Looks like the Polyfills are not loaded for post-update commands then. That's a pity.

@perice
Copy link

perice commented Jul 27, 2021

Same thing:

Fatal error: Uncaught Error: Call to undefined function Symfony\Component\Yaml\str_contains() in /var/www/site/vendor/symfony/symfony/src/Symfony/Component/Yaml/Parser.php:214

Trying to upgrade Symfony v4.4.25 => v4.4.28
Composer version 2.0.7
PHP version 7.3.25

@crmpicco
Copy link
Author

@crmpicco What version of Composer are you using?

composer --version
Composer version 2.1.5 2021-07-23 10:35:47

@ghost
Copy link

ghost commented Jul 27, 2021

I am affected by this too, but not on all systems (with the same source).

I upgraded from 5.3.0 to 5.3.4.

local dev (working)

Composer version 2.1.3 2021-06-09 16:31:20

remote dev (not working)

Composer version 2.1.5 2021-07-23 10:35:47

I tested both php 7.2.31 and 7.3.19 on both dev systems


EDIT: I pinned 5.3.0 for now, that version continues to work as expected

@crmpicco
Copy link
Author

Looks like the Polyfills are not loaded for post-update commands then. That's a pity.

Is this a new thing? Wouldn't they be available project-wide?

@jurgenhaas
Copy link

Same here. Also, not only str_contains causes this issue but also str_starts_with and probably others that would "normally" be covered by polyfills.

@nicolas-grekas
Copy link
Member

I'd be great to understand why this happens. This is strange to me.

@NicoHaase
Copy link
Contributor

Just as an idea: could it be that the polyfill file is read before updating (through any include stuff), and not a second time after updating, as it already got included through any of the ways Composer's autoloader could include it?

@jurgenhaas
Copy link

It's not only happening for post-update commands. I have some commands defined by Composer\Plugin\Capability\CommandProvider that I call directly, which show the same error.

If I explicitly call require_once 'vendor/symfony/polyfill-php80/bootstrap.php';, the problem is gone.

@derrabus
Copy link
Member

Reproducer: https://github.com/derrabus/yaml-reproducer

  • Run composer install with PHP 8.0: ✅
  • Run composer install with PHP 7.4: 💥

@cs278
Copy link
Contributor

cs278 commented Jul 27, 2021

I think this is a bug in Composer, it doesn't load the bootstrap.php files form the Symfony polyfill packages. composer/composer#10024

@helhum
Copy link
Contributor

helhum commented Jul 27, 2021

I'd be great to understand why this happens. This is strange to me.

The reason is pretty straightforward. There is a difference between runtime code (code that execute after inclusion of the vendor/autoload.php file) and build time code (code that is executed when composer builds all its files).

Build time code is typically provided by Composer plugins. For this code to work (classes to be autoloaded), Composer registers a temporary PHP autoloader, which works similar to the one that is registered when including the vendor/autoload.php file, with the exception that "include files" are not included.

As I outlined in the Composer issue tracker, I don't think there is much that can be done on Composer side.

I see two possible solutions:

  1. Composer Plugin authors can not use Symfony Components (that require include files)
  2. Symfony Components that can be useful for Composer build time code, must not rely on include files

For me this also shows that using polyfills (or any globally defined function) has its limitations and should not be introduced lightly (at least not in a bugfix version, as maintainer of other libraries can not define dependencies reliably any more, when bugfix versions can break for bugfix releases)

@helhum
Copy link
Contributor

helhum commented Jul 27, 2021

Of course I'm biased, but I don't see that the benefits such cleanups provide, justify issues introduced with requiring a PHP8 polyfill when using these libs with PHP versions < 8.

At least it should be considered doing such cleanups later in a release cycle and for sure not for bugfix releases.

As of now such changes mean:

  • All SF code that uses include files can not be used for Composer Plugins
  • There is a performance impact for polyfills, meaning that performance will be reduced

@helhum
Copy link
Contributor

helhum commented Jul 27, 2021

Another side note: The underlying pain point here isn't a polyfill, breakage or performance impacts, but IMHO the growing usage of globally defined functions. Global functions are still odd in PHP, as they require to be defined upfront making code that depends these function depend on globally initialized state.

Unless PHP intself finds a way to autoload functions in an acceptable way, my stance is to stay away from global functions as far as possible and use static methods instead.

@metaer

This comment has been minimized.

@helhum

This comment has been minimized.

@metaer

This comment has been minimized.

@metaer

This comment has been minimized.

@maikschneider

This comment has been minimized.

@maikschneider

This comment has been minimized.

@helhum
Copy link
Contributor

helhum commented Jul 27, 2021

Introduced with v5.3.4, v5.2.12, v4.4.27

@derrabus
Copy link
Member

@maikschneider @helhum Please don't turn this issue into a chat. Let's discuss how to solve the problem described here.

@derrabus
Copy link
Member

Okay, since this is apparently the way Composer works, I suggest we revert the introduction of the Polyfill in Yaml and Dotenv at least. Are there any other components that we would expect to be used in composer plugins?

@derrabus
Copy link
Member

#42296

@derrabus derrabus linked a pull request Jul 27, 2021 that will close this issue
@symfonyaml

This comment has been minimized.

@simonschaufi
Copy link

simonschaufi commented Jul 27, 2021

If there are methods used which are only available in PHP 8, why is the composer dependency then saying "php": ">=7.2.5",
instead of "php": ">=8.0.0",?

https://github.com/symfony/dotenv/blob/5.3/composer.json#L19

I also consider this a breaking change and it should NOT be tagged as a bugfix release.

@derrabus
Copy link
Member

Thank you for your input, @simonschaufi. You are more than welcome to test my pull request.

@IanAtOcucom
Copy link

This is also a problem with Symfony/DotEnv

@sudo-barun
Copy link

I am also facing same problem when using composer script from incenteev/composer-parameter-handler:2.1.4.

This is happening due to changes in e585b26 and also due to the fact that composer does not autoload files from symfony/polyfill-php80 when running composer script.

To fix the problem, I am using fixed version of symfony as symfony/symfony:5.3.3 for the moment until the symfony teams fix this problem.

fabpot added a commit that referenced this issue Jul 29, 2021
This PR was merged into the 4.4 branch.

Discussion
----------

[Dotenv][Yaml] Remove PHP 8.0 polyfill

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #42280
| License       | MIT
| Doc PR        | N/A

This is a partial revert of #41576 and #41973.

Commits
-------

08ecbf5 Remove polyfills from Yaml and Dotenv
@fabpot fabpot closed this as completed Jul 29, 2021
@echavaillaz
Copy link

Same problem for me with symfony/expression-language, I am forced to downgarde to 5.1.11.

Can you have a look?

Thanks

@jderusse
Copy link
Member

Are there any other components that we would expect to be used in composer plugins?

Well.. All components could be used at some point in somebody's plugin.
We should either:

  • stop using polyfill in components.
  • update composer to load bootstrap files at build time
  • find another way to load the bootstrap file

nicolas-grekas added a commit that referenced this issue Aug 19, 2021
…lmann)

This PR was submitted for the 5.3 branch but it was merged into the 4.4 branch instead.

Discussion
----------

[ExpressionLanguage] [Lexer] Remove PHP 8.0 polyfill

| Q             | A
| ------------- | ---
| Branch       | 5.3
| Bug fix      | yes
| New feature  | no
| Deprecations | no
| Tickets       | Fix #42280
| License       | MIT
| Doc PR        | N/A

This is a partial revert of #41576 and is a followup to #42296

Commits
-------

d2f39e9 Remove polyfills from ExpressionLanguage
TomaszGasior added a commit to TomaszGasior/create-symfony-project that referenced this issue Sep 7, 2021
The newest versions of Symfony HTTP client use PHP 8 functions
and require PHP 8 polyfill which does not work in context
of Composer plugin. :(

symfony/symfony#42280
composer/composer#10024
fabpot added a commit that referenced this issue Nov 5, 2021
…s (xabbuh)

This PR was merged into the 5.4 branch.

Discussion
----------

[Yaml] revert using functions provided by polyfill packages

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #43943
| License       | MIT
| Doc PR        |

This reverts #41431 for the same reason for which we merged #42296 (see #42280 and composer/composer#10024 for more information).

Commits
-------

3b9b700 revert using functions provided by polyfill packages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.