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

Different php versions for development and production #5163

Closed
1ed opened this issue Apr 7, 2016 · 33 comments
Closed

Different php versions for development and production #5163

1ed opened this issue Apr 7, 2016 · 33 comments

Comments

@1ed
Copy link
Contributor

1ed commented Apr 7, 2016

With the following composer.json:

{
    "require": {
        "php": ">=5.3.3",
        "friendsofsymfony/user-bundle": "v2.0.0-alpha1",
        "symfony/symfony": "^2.6"
    },
    "require-dev": {
        "fabpot/php-cs-fixer": "^1.5"
    },
    "config": {
        "platform": {
            "php": "5.3.3"
        }
    }
}

When I run this command:

composer update -vvv

I get this output:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - fabpot/php-cs-fixer v1.5.2 requires php >=5.3.6 -> your PHP version (5.4.27) overriden by "config.platform.php" version (5.3.3) does not satisfy that requirement.
    - fabpot/php-cs-fixer v1.5.1 requires php >=5.3.6 -> your PHP version (5.4.27) overriden by "config.platform.php" version (5.3.3) does not satisfy that requirement.
    - fabpot/php-cs-fixer v1.5 requires php >=5.3.6 -> your PHP version (5.4.27) overriden by "config.platform.php" version (5.3.3) does not satisfy that requirement.
    - Installation request for fabpot/php-cs-fixer 1.5.* -> satisfiable by fabpot/php-cs-fixer[v1.5, v1.5.1, v1.5.2].

There is a way to handle this and use different php version for require-dev than require? If I add
"php": ">=5.4", under require-dev, I get

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - This package requires php >=5.4 but your PHP version (5.3.3) does not satisfy that requirement.
  Problem 2
    - fabpot/php-cs-fixer v1.5.2 requires php >=5.3.6 -> your PHP version (5.4.27) overriden by "config.platform.php" version (5.3.3) does not satisfy that requirement.
    - fabpot/php-cs-fixer v1.5.1 requires php >=5.3.6 -> your PHP version (5.4.27) overriden by "config.platform.php" version (5.3.3) does not satisfy that requirement.
    - fabpot/php-cs-fixer v1.5 requires php >=5.3.6 -> your PHP version (5.4.27) overriden by "config.platform.php" version (5.3.3) does not satisfy that requirement.
    - Installation request for fabpot/php-cs-fixer 1.5.* -> satisfiable by fabpot/php-cs-fixer[v1.5, v1.5.1, v1.5.2].

I think it would be great if the platform attribute would be taken into account for the require key only and not for require-dev.

@curry684
Copy link
Contributor

curry684 commented Apr 7, 2016

How is CI going to work if it runs your tests on 5.3 with PHPunit 5+ requiring >=5.5?

To illustrate, think of this:

{
    "require": {
        "php": ">=5.3.3",
        "friendsofsymfony/user-bundle": "v2.0.0-alpha1",
        "symfony/symfony": "^2.6"
    },
    "require-dev": {
        "phpunit/phpunit": ">=4.2"
    },
    "config": {
        "platform": {
            "php": "5.3.3"
        }
    }
}

If we were to implement this it would most definitely install PHPunit 5 on some CI images instead of 4.x consistently on all of them.

(yes of course this is stupid not to use ^4.2 but it illustrates the point of unintended consequences)

@alcohol
Copy link
Member

alcohol commented Apr 8, 2016

require and require-dev should both follow the same platform requirements. It makes no sense to split those up.

@alcohol alcohol closed this as completed Apr 8, 2016
@1ed
Copy link
Contributor Author

1ed commented Apr 8, 2016

This is from the docs:

platform

Lets you fake platform packages (PHP and extensions) so that you can emulate a production env or define your target platform in the config. Example: {"php": "5.4", "ext-something": "4.0"}

What is the purpose of the platform attribute then? In my interpretation it lies about the platform package versions so the developer can require packages without taking care about checking every package platform requirements meets the production environment and the developer can use other php version than the production one. require-dev requirements should not run in production so why should follow the same platform requirements? What would be a valid use case for using platform if mine is not valid?

@curry684
Copy link
Contributor

curry684 commented Apr 8, 2016

What is the purpose of the platform attribute then

It allows you to mimic intended distribution environments on your development machine, lying about what's really installed to ensure only compatible packages are selected and locked.

Say you're building an application to be distributed on PHP 5.4 or later. You include symfony/symfony:^2.7 as 3.0+ requires PHP 5.5. However, Symfony itself has a lot of recursive dependencies, which may also match versions requiring PHP7+. Now if your dev machine has PHP7 you will get those versions still, test against them, and commit them in your lockfile.

By overriding the platform requirements during development you can guarantee that the final application can be installed and run correctly on those lower requirements.

This is also the exact same reason require-dev needs to follow the same constraints, as it may introduce the same issues for different developers. What if you and a colleague work on the same project, but you have PHP 5.6 locally and he has 7.0? You'd be committing different composer.lock files in turn all the time.

@tfrommen
Copy link
Contributor

tfrommen commented Jun 17, 2016

Re @alcohol:

require and require-dev should both follow the same platform requirements. It makes no sense to split those up.

In my opinion, it absolute does make sense.
One of the simplest examples would be that you have software supporting PHP 5.4, but in your tests you would like to make use of the static class property (introduced in PHP 5.5). So one would set the platform for production code to PHP 5.4, and for development either to PHP 5.5 (or later), or remove the constraint altogether. See the following example config:

{

  "require": {
    "php": ">=5.4"
  },
  "require-dev": {
    "php": ">=5.5",
    "phpunit/phpunit": "~4.8|~5.1"
  },
  "config": {
    "platform": {
      "php": "5.4"
    },
    "platform-dev": {
      "php": "*"
    },
  }

}

It would really be nice if this could be revisited once again.

@alcohol
Copy link
Member

alcohol commented Jun 17, 2016

You can make use of the static property and php 5.5 features without adding the >=5.5 requirement to your require-dev section. Your regular require says you need at least 5.4, so nothing is stopping you from using those features.

Your opinion is noted, but your example is flawed.

@tfrommen
Copy link
Contributor

tfrommen commented Jun 17, 2016

That's right. I just provided a use case. The problem lies with the fact that I can't even use development packages that require PHP 5.5+ - because the platform is set to PHP 5.4.

@alcohol
Copy link
Member

alcohol commented Jun 17, 2016

Or you could read the documentation; --ignore-platform-requirements.

@tfrommen
Copy link
Contributor

tfrommen commented Jun 17, 2016

Sorry, but what's this subliminal reproach all about? For more than half of what you define in the composer.json there's an according CLI flag etc.
But I get it. You didn't need this so far, so there most probably isn't any use in it, right?

@alcohol
Copy link
Member

alcohol commented Jun 17, 2016

Correct, the use case is very specific. We really want to avoid having to support every single feature just because one or two individuals somehow found themselves in a situation where it might be applicable. Especially when there are so many ways around it already to achieve a workable resolution.

@curry684
Copy link
Contributor

Also, the use case is flawed. My examples show cases where this would definitely and painfully break sane development workflows. This does not invalidate your use case, but it does invalidate the CR to Composer as a whole.

@Nessworthy
Copy link

Nessworthy commented May 25, 2017

Hmm.
My developer environment runs PHPUnit 6.1, which has a minimum support of PHP7.
My production environment runs PHP 5, but the tests are written to support PHPUnit 6.1 because they're only executed as part of CI / dev, which run on PHP 7.

With these settings, there's no way I can tell composer that my dev environment should support 7 for phpunit, but should be restricted to 5 for non-dev packages.

If upgrading prod is out of the picture, what other workaround do I have bar rewriting all of my tests for php5 and downgrading the global phpunit install to work with the prod environment's version? Even though it's not actually used in production, my dev dependencies would be forced to adhere to production versions.

Why should require and require-dev have to adhere to the same platform versions?

@Seldaek
Copy link
Member

Seldaek commented May 25, 2017

@Nessworthy why? Because it's a pretty bad idea to develop on a different version than what you run on prod. You are working with different features, different bugs, etc. than you have in prod, and that might lead to unexpected issues when deploying. It's also a bad idea to run your CI on a different environment than the production one IMO. You can work around this in many ways if you really want (e.g. using different json files, or installing phpunit separately), so I don't see this as a problem in Composer that it doesn't enable bad practices.

@Seldaek
Copy link
Member

Seldaek commented May 25, 2017

Another point is that your time would be better spent upgrading production servers to a current php version rather than on wasting everyone's time arguing about this here. We technically can not fix this so it's not worth discussing.

@Nessworthy
Copy link

Your second comment is absolutely superfluous apart from that last point. I get it though, this to me is the first set of reasons in this thread which explain why it's not a good idea in general, so thanks.

@forceedge01
Copy link

Scary that we have examples of prod using a different version of PHP as to the CI or dev environment. I don't think that should ever be the case! You can develop something on your local env supporting the language constructs for PHP7, CI would say 'heh nicely done' and prod would go boom because PHP5 doesn't support it! Extremely fiddly area..

@olivertappin
Copy link

olivertappin commented Jan 23, 2018

I think anyone who believes, in an enterprise setup, that all environments can miraculously be updated to the same versions of a particular package (whether that be PHP or a specific module) is living in la-la land. Realistically, it takes months to upgrade and test a whole platform (500+ servers) across different DCs for QA, Staging and Production environments. This is a very real need for larger companies (not just those who are working on their development machine and a single production server).

Although this example only talks about require-dev and require, the ability to choose certain packages for certain environments with specific versions that all need to be supported is an extremely fiddly scenario which needs addressing properly.

@curry684
Copy link
Contributor

Good to know just about every big dotcom out there is living in la-la land. Except that, if you have 100+ servers, those companies do all this in 5 minutes through Chef, Salt or Puppet.

Patching 500 webservers at once can be as simple as salt -G role:webserver cmd.run composer install -o here in la-la land.

https://12factor.net/dev-prod-parity

@geek-merlin
Copy link

There are some very informative points in this issue. Thank you all!
That said, in the realms of such a wonderful tool as composer is, i'd wish for a more graceful overall tone.

@danieliser
Copy link

I'm gonna weigh in here with the ultimate use case, WordPress plugins and other prepackaged software. End of story.

A WordPress plugin can be built using composer packages, in fact many are. But unlike all the scenarios you pointed to, you can't just "spend your time better". This code could literally run on any type of PHP server config >5.6, and I'm not upgrading 500k users web servers because they use an older version.

WordPress core itself has a minimum PHP version requirement of 5.6, but many of the testing suites and dev tools built around it, including composer packages that never will be bundled into production released code which is prepackaged software.

For me to have to run --ignore-platform-requirements on each composer require, composer install or composer update is asinine and completely defeats the purpose as it will let require packages bypass the same check we are hoping to enfoce.

Further because one package in require-dev has a min PHP version of 7.2+, but the platform will be anywhere from 5.6-7.4+, unless I add the --ignore-platform-requirements flag to every call to install, update, or require, nothing works.

Sure I can remove the config.platform.php version, but then I'm left to manually check all require packages for version compatibility. Basically could just install packages manually and require them myself too, but that isn't what I chose to use composer for, is it?

@Seldaek
Copy link
Member

Seldaek commented Jun 1, 2020

@danieliser IMO for that use case, you should modify/set the config.platform.php value in CI/build steps where appropriate, so that your released plugins ships with versions guaranteed to work on 5.6, but otherwise things relying on require-dev can just run commands without --ignore-platform-reqs.

We do something similar for Composer for example, which has to ship bundled dependencies working on 5.3.3+. We have that set as the platform version by default, but then for our CI builds on php7 and above we modify that to make sure higher versions of the dependencies can be installed, so that deprecation warnings can be fixed, and overall compatibility issues fixed, at least in the dev tools like phpunit etc.

@danieliser
Copy link

@Seldaek - Interesting way to go. My only concern then becomes we have to maintain multiple versions of our code base in the case that libraries make breaking changes between PHP versions.

Will play around with that idea. I wonder if we go that route can we just leave the config.platform.php unset until we build for CI and release, then set it on the fly as you suggested.

@Seldaek
Copy link
Member

Seldaek commented Jun 2, 2020 via email

@scorgn
Copy link

scorgn commented Sep 13, 2020

I want to chime in here with the reverse case. If I am developing a library that requires psr/http-client-implementation, as an example, I will need to add an implementation for that to my require-dev. Now let's say the implementation I decide to use has a minimum PHP version requirement of 7.2. But the library itself doesn't have any code or packages that restrict the version to 7.2. I am now having to update my PHP version constraint to ^7.2 forcing all the users to use PHP 7.2 when in reality - the package can be used with PHP 7.1.

@Seldaek
Copy link
Member

Seldaek commented Sep 14, 2020

@ShawnCorrigan IMO this example is kinda invalid, because if you require-dev something that requires 7.2, then you cannot run your test suite on 7.1, and thus cannot check that it works there.

If it wasn't for that though, you are free to require 7.1 in your package, even if it has something requiring 7.2 in require-dev. You can't put your config.platform.php to 7.1 though as that would break the dependency resolution, but that's the only limitation I see (aside from the CI as I explained above).

@scorgn
Copy link

scorgn commented Sep 14, 2020

I suppose that would be poor practice in that case. Although another example could be a logging library which is not used in tests but also only used in development. But that is probably a very small and obscure use case.

@JoyceBabu
Copy link

JoyceBabu commented Jan 13, 2021

There are a few use cases where using an higher version of PHP on the dev environment makes sense.

Rector allows developing in PHP 8 with latest syntactical sugar, but then transpiling the code to run on lower version.

https://blog.logrocket.com/transpiling-php-code-from-8-0-to-7-x-via-rector/

Also, sometimes there are dependencies that needs to be run only on developer machine. For example,

  • A dependency used in a git hook. For example, PHP-CS-Fixer run on pre-commit hook to fix CS errors.
  • A database migration generator (https://github.com/odan/phinx-migrations-generator). Only the generated migration is committed and run on the production server.

@Luc45
Copy link

Luc45 commented Nov 10, 2022

My scenario:

  • I need to install a snapshot testing package that requires PHP 7.4
  • My application can work perfectly fine with PHP 7.2
  • I don't want to bump my application's minimum PHP version to 7.4 just to use this snapshot testing package
  • If I run composer update --ignore-platform-reqs, I end up with PHP 8.1 packages in the mix, which I don't want.

In my scenario, this suggestion would be perfect.

@curry684
Copy link
Contributor

If your dev env requires snapshot images you shouldn't be supporting EOL PHP versions as it means you are actively breaking your test suite by not testing anything on those EOL PHP versions, thereby invalidating your claim that your application still works fine on them. You simply do and can not know that.

https://www.php.net/supported-versions.php

@Luc45
Copy link

Luc45 commented Nov 10, 2022

If your dev env requires snapshot images you shouldn't be supporting EOL PHP versions as it means you are actively breaking your test suite by not testing anything on those EOL PHP versions

I think there's a middle ground there, but that's a good point. 🤔

https://www.php.net/supported-versions.php

I would love to use PHP 8.1, I just can't. I work on an application that is shipped on client's servers, and unfortunately, the end users might not update the PHP versions on their servers. It doesn't make sense from a business perpsective to ignore the users that are not using the supported PHP versions.

image

@curry684
Copy link
Contributor

From a business perspective my recommendation would be to send a mail out now stating that you are sunsetting new feature support for end of life PHP versions per January 1st, branch out the current version purely for support purposes, and upgrade your feature branch to PHP 7.4. Set up a roadmap and communicate it, stating that henceforth new features will only be released for supported PHP versions, and maintain your 'support' and 'feature' branches separately from now on. This will eliminate all compatibility issues, and remember even PHP 7.4 is already in extended support which will end in 16 days (!).

You have a business issue with supporting too many outdated PHP versions, not a technical issue with Composer, and your customers are not upgrading simply because you are not requiring them. This is why you still need to care about PHP 5.2 which went end of life 11 years ago and will need to support PHP 5.6 until 2030 unless you change policy.

@Luc45
Copy link

Luc45 commented Nov 11, 2022

@curry684 What you said makes perfect sense. I develop software for WordPress, the chart above are from the PHP versions running WP.

If we can trust this source, as of 2022, there are about 1.4 billion total websites on the web. More than 455 million sites use WordPress. There is an active coordinated effort in asking users to upgrade their PHP versions and asking hosting providers to do that as well. WP as a project watches the PHP version chart over time to make decisions such as dropping PHP versions, etc. Officially, it supports PHP 5.6 to 8.2, but I've heard rumors this would be bumped to something like 7.1 or 7.2 soon.

PHP 7.4 was released on 28 Nov 2019. Imagine if WP dropped support for all the websites and plugins (60k+ libraries) after just 2 years?

Windows for instance is so big because it's very stable from a software perspective. When you write a software for it, you can be certain that it will keep working for a reasonable amount of time. Rewriting software for the purpose of rewriting is expensive and sometimes not very lucrative. I'm sure a lot of people would be pissed off if WP dropped support entirely to older versions. I think 7.2 is still within a reasonable time frame.

My point is that there are legit real-world use cases for supporting older PHP versions. I would love to have a different PHP version constraint for require-dev, so that I can develop using my upper PHP version bounder on my test code and test libraries for instance.

@curry684
Copy link
Contributor

PHP 7.4 was released on 28 Nov 2019. Imagine if WP dropped support for all the websites and plugins (60k+ libraries) after just 2 years?

You don't need to drop support. You need to drop full support. Symfony will still be supporting its 4.x branch, which was initially released in november 2017, for more than a year. That's 6 years total.

It hasn't gotten a new feature since november 2019 though, and Symfony 6.2 requires PHP 8.1 and has all the most modern dependencies.

Wordpress isn't adding new features or dependencies to its 3.x, 4.x of 5.x branches, but 3.8.40 was still released 4 weeks ago.

The core remains - do as WP and Symfony do, and separate your support and feature branches. It solves all your problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests