Reputation: 8560
I want something like this:
env('APP_ENV');
setenv('APP_ENV', 'testing');
env('APP_ENV');
Output :
staging
testing
I find one answer How to change variables in the .env file dynamically in Laravel? but here .env is saved permanently, I don't want to save permanently. How phpunit is doing this ? Because I can put in phpunit.xml this :
...
<php>
<env name="APP_ENV" value="testing"/>
</php>
....
And env('APP_ENV') gives me 'testing'...
Upvotes: 8
Views: 17412
Reputation: 6013
Considering laravel keeps messing around env() helper every now and then, its easier to simply use getenv()
instead of env()
. Then it should be ok to set the env var any time using putenv()
.
Upvotes: 0
Reputation: 21
Notice:
env('AAA') = getenv('AAA')
→ To set the value of the variable AAA, simply use putenv('AAA', 'true');
→ env('AAA') will become TRUE
You can check the details of getenv() here https://github.com/laravel/framework/blob/5.7/src/Illuminate/Support/helpers.php
From Laravel 5.8 onward, env() no longer uses getenv() anymore.
Therefore, env('AAA') != getenv('AAA')
→ So even though we use putenv('AAA', 'true');
the value of env('AAA') will not change.
Because the behavior of the env() becomes
env('AAA') = Env::getRepository()->get('AAA');
→ To set the value of the variable AAA, use Env::getRepository()->set('AAA','true')
→ env('AAA') will become TRUE
You can check the details of getenv() of Laravel 5.8 here https://github.com/laravel/framework/blob/5.8/src/Illuminate/Support/helpers.php
Upvotes: 1
Reputation: 7800
Laravel .env
file values are read by Laravel at the application bootstrap time and stored in the PHP $_ENV
global array under the respective keys.
You can change any of those Laravel's (or other $_ENV's) values as simple as:
// Assign the key's new value in the $_ENV global array
$_ENV['DB_CONNECTION'] = 'sqlite';
However if Laravel would take your change into account or not depends on the place in the code where you put this assignment.
Development, Staging, Production Environments:
Changing env values dynamically in memory for these environments is a bad idea.
Nevertheless to make this change you have to put your assignements in the Laravel bootstrap file before the framework instantiates LoadEnvironmentVariables class (for Lumen, the instantiation happens in /bootstrap/app.php
file, for Laravel you could put your changes in the same file before application instantiation).
Testing Environment
However for testing environment changing env variables can be sometimes useful.
On top of the PHPUnit capability to change env variables at the test loading (as an example see the Laravel's phpunit.xml
in your project folder):
<php>
<env name="DB_CONNECTION" value="sqlite"/>
</php>
you can change the variables in the PHPUnit's setUp
function, (that in Laravel also bootstraps the application - note the tests extend the Laravel TestCase
) like the following:
public $savedDBConnection;
public function setUp():void
{
$this->savedDBConnection = $_ENV['DB_CONNECTION'];
$_ENV['DB_CONNECTION'] = 'mysql';
parent::setUp();
}
Caveat
Rather often you may face the unpleasant side effects of such dynamic changes (e.g. you test with in memory database and temporarily switch to on-disk test DB and some other test's database refresh erases your on-disk test DB data).
To avoid this you have to save the variables before you change them in setUp
method (as shown above) and restore them in tearDown
method, like this:
public function tearDown():void
{
$_ENV['DB_CONNECTION'] = $this->savedDBConnection;
parent::tearDown();
}
Alternative
There is the other sometimes more applicable approach to change your .env
variables for testing environment (credits go here.): create the .env.testing
file and load it when in tests. Briefly, add the following colde as explained in the comments
// Add in tests/TestCase.php::createApplication() method
// below $app = require __DIR__.'/../bootstrap/app.php' call.
if (file_exists(dirname(__DIR__) . '/.env.testing')) {
(new \Dotenv\Dotenv(dirname(__DIR__), '.env.testing'))->load();
}
Now it is enough information to decide whether, when or how one needs / can change the env variables dynamically.
Upvotes: 4
Reputation: 8560
putenv() work like a charm :
echo env('APP_ENV');
putenv('APP_ENV=testing');
echo env('APP_ENV');
Output:
staging
testing
.env file is unattached ...
Upvotes: 7
Reputation: 116
Dotenv is immutable, so you cannot change value that is already assigned. (https://github.com/vlucas/phpdotenv#immutability)
PHPUnit is setting this values during bootstrap, before laravel is started. Laravel dotenv is running in immutable mode, so values already set, are not overridden.
Upvotes: 2