diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 873dc682569b1..85358cfbf66b4 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -45,6 +45,12 @@ Doctrine Bridge * Passing an `IdReader` to the `DoctrineChoiceLoader` when the query cannot be optimized with single id field has been deprecated, pass `null` instead * Not passing an `IdReader` to the `DoctrineChoiceLoader` when the query can be optimized with single id field has been deprecated +Dotenv +------ + + * First parameter of `Dontenv::__construct()` will change from `true` to `false` in Symfony 5.0. A deprecation warning + will be triggered if no parameter is used. Use `$usePutenv=true` to upgrade without breaking changes. + EventDispatcher --------------- diff --git a/src/Symfony/Component/Dotenv/CHANGELOG.md b/src/Symfony/Component/Dotenv/CHANGELOG.md index 3d3546f76c63d..296f029e7a9ac 100644 --- a/src/Symfony/Component/Dotenv/CHANGELOG.md +++ b/src/Symfony/Component/Dotenv/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * deprecated use of `putenv()` but default. This feature will be opted-in with a constructor argument to `Dotenv`. + 4.2.0 ----- diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 697e09ec0b443..e980544f73c1b 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -35,6 +35,21 @@ final class Dotenv private $data; private $end; private $values; + private $usePutenv = true; + + /** + * @var bool If we should use `putenv()` to define environment variables + * or not. Since Symfony 5.0 the default value is false + * because `putenv()` is not thread safe. + */ + public function __construct(bool $usePutenv = true) + { + if (0 === \func_num_args()) { + @trigger_error(sprintf('The default value of "$usePutenv" argument of "%s\'s constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly.', __METHOD__), E_USER_DEPRECATED); + } + + $this->usePutenv = $usePutenv; + } /** * Loads one or several .env files. @@ -126,7 +141,10 @@ public function populate(array $values, bool $overrideExistingVars = false): voi continue; } - putenv("$name=$value"); + if ($this->usePutenv) { + putenv("$name=$value"); + } + $_ENV[$name] = $value; if ($notHttpName) { $_SERVER[$name] = $value; @@ -140,7 +158,11 @@ public function populate(array $values, bool $overrideExistingVars = false): voi if ($updateLoadedVars) { unset($loadedVars['']); $loadedVars = implode(',', array_keys($loadedVars)); - putenv('SYMFONY_DOTENV_VARS='.$_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars); + $_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars; + + if ($this->usePutenv) { + putenv('SYMFONY_DOTENV_VARS='.$loadedVars); + } } } diff --git a/src/Symfony/Component/Dotenv/README.md b/src/Symfony/Component/Dotenv/README.md index 244ed7700a14e..38dde84bc4d95 100644 --- a/src/Symfony/Component/Dotenv/README.md +++ b/src/Symfony/Component/Dotenv/README.md @@ -2,7 +2,7 @@ Dotenv Component ================ Symfony Dotenv parses `.env` files to make environment variables stored in them -accessible via `getenv()`, `$_ENV`, or `$_SERVER`. +accessible via `$_ENV`, `$_SERVER` and optionally `getenv()`. Resources --------- diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 36c0af252094a..8d308c415925c 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -22,7 +22,7 @@ class DotenvTest extends TestCase */ public function testParseWithFormatError($data, $error) { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); try { $dotenv->parse($data); @@ -62,7 +62,7 @@ public function getEnvDataWithFormatErrors() */ public function testParse($data, $expected) { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $this->assertSame($expected, $dotenv->parse($data)); } @@ -193,7 +193,7 @@ public function testLoad() file_put_contents($path1, 'FOO=BAR'); file_put_contents($path2, 'BAR=BAZ'); - (new Dotenv())->load($path1, $path2); + (new Dotenv(true))->load($path1, $path2); $foo = getenv('FOO'); $bar = getenv('BAR'); @@ -224,7 +224,7 @@ public function testLoadEnv() // .env file_put_contents($path, 'FOO=BAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('BAR', getenv('FOO')); $this->assertSame('dev', getenv('TEST_APP_ENV')); @@ -232,33 +232,33 @@ public function testLoadEnv() $_SERVER['TEST_APP_ENV'] = 'local'; file_put_contents("$path.local", 'FOO=localBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('localBAR', getenv('FOO')); // special case for test $_SERVER['TEST_APP_ENV'] = 'test'; - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('BAR', getenv('FOO')); // .env.dev unset($_SERVER['TEST_APP_ENV']); file_put_contents("$path.dev", 'FOO=devBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('devBAR', getenv('FOO')); // .env.dev.local file_put_contents("$path.dev.local", 'FOO=devlocalBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('devlocalBAR', getenv('FOO')); // .env.dist unlink($path); file_put_contents("$path.dist", 'BAR=distBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('distBAR', getenv('BAR')); putenv('FOO'); @@ -290,7 +290,7 @@ public function testOverload() file_put_contents($path1, 'FOO=BAR'); file_put_contents($path2, 'BAR=BAZ'); - (new Dotenv())->overload($path1, $path2); + (new Dotenv(true))->overload($path1, $path2); $foo = getenv('FOO'); $bar = getenv('BAR'); @@ -310,7 +310,7 @@ public function testOverload() */ public function testLoadDirectory() { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->load(__DIR__); } @@ -318,7 +318,7 @@ public function testServerSuperglobalIsNotOverriden() { $originalValue = $_SERVER['argc']; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['argc' => 'new_value']); $this->assertSame($originalValue, $_SERVER['argc']); @@ -329,7 +329,7 @@ public function testEnvVarIsNotOverriden() putenv('TEST_ENV_VAR=original_value'); $_SERVER['TEST_ENV_VAR'] = 'original_value'; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['TEST_ENV_VAR' => 'new_value']); $this->assertSame('original_value', getenv('TEST_ENV_VAR')); @@ -339,7 +339,7 @@ public function testHttpVarIsPartiallyOverriden() { $_SERVER['HTTP_TEST_ENV_VAR'] = 'http_value'; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['HTTP_TEST_ENV_VAR' => 'env_value']); $this->assertSame('env_value', getenv('HTTP_TEST_ENV_VAR')); @@ -351,7 +351,7 @@ public function testEnvVarIsOverriden() { putenv('TEST_ENV_VAR_OVERRIDEN=original_value'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['TEST_ENV_VAR_OVERRIDEN' => 'new_value'], true); $this->assertSame('new_value', getenv('TEST_ENV_VAR_OVERRIDEN')); @@ -373,7 +373,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() unset($_SERVER['DATABASE_URL']); putenv('DATABASE_URL'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['APP_DEBUG' => '1', 'DATABASE_URL' => 'mysql://root@localhost/db']); $this->assertSame('APP_DEBUG,DATABASE_URL', getenv('SYMFONY_DOTENV_VARS')); @@ -390,7 +390,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() unset($_SERVER['DATABASE_URL']); putenv('DATABASE_URL'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['APP_DEBUG' => '0', 'DATABASE_URL' => 'mysql://root@localhost/db']); $dotenv->populate(['DATABASE_URL' => 'sqlite:///somedb.sqlite']); @@ -406,7 +406,7 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() putenv('BAZ=baz'); putenv('DOCUMENT_ROOT=/var/www'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['FOO' => 'foo1', 'BAR' => 'bar1', 'BAZ' => 'baz1', 'DOCUMENT_ROOT' => '/boot']); $this->assertSame('foo1', getenv('FOO')); @@ -414,4 +414,21 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() $this->assertSame('baz1', getenv('BAZ')); $this->assertSame('/var/www', getenv('DOCUMENT_ROOT')); } + + /** + * @group legacy + * @expectedDeprecation The default value of "$usePutenv" argument of "%s's constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly. + */ + public function testDeprecationWarning() + { + new Dotenv(); + } + + public function testNoDeprecationWarning() + { + $dotenv = new Dotenv(true); + $this->assertInstanceOf(Dotenv::class, $dotenv); + $dotenv = new Dotenv(false); + $this->assertInstanceOf(Dotenv::class, $dotenv); + } }