'Using strategy pattern with environment variable laravel

I am currently learning about design patterns and I came across strategy pattern. I understood it, but now I want to know what would be the best solution to change strategy at runtime. Is it good solution to use ENV variables? Example:

interface Logger{
    public function log();
}


class SomeOtherLogger implements Logger {

public function log(){
    echo "Logging to something else";
 }
}


class FileLogger implements Logger {

public function log(){
    echo "Logging to file";
 }
}

class Main{
public function doSomething(Loggers $logger){
    $logger->log();    
 }
}

$main = new main();
$main->doSomething(new FileLogger);

One thing that came across my mind is to use environment variable, but I am not sure what is the best way to do it, this one doesn't seem right to me.

$loggingStrategy = env('LOGGING_TYPE') . 'Logger';
$main = new main();
$main->doSomething(new $loggingStrategy);


Solution 1:[1]

If you are using Laravel I have a better solution. I hope it works for you:

Laravel has a Manager base class that you can use to implement a strategy pattern. Consider we want to great users depends on their languages.

First, let's implement our language classes:

namespace App\Welcome;

class English
{
    public function great()
    {
        return 'Hi!';
    }
}

and for German:

namespace App\Welcome;

class German
{
    public function great()
    {
        return 'Halo!';
    }
}

Now we create Welcome class that extends Laravel Manager base class:

namespace App;

use App\Welcome\English;
use App\Welcome\German;
use Illuminate\Support\Manager;

class Welcome extends Manager
{
    public function getDefaultDriver()
    {
        return 'english';
    }

    public function createGermanDriver()
    {
        return new German();
    }

    public function createEnglishDriver()
    {
        return new English();
    }
}

Now you can you can use strategy pattern and define a default driver for your Welcome class. If you want to change the driver at runtime you can use driver method on the welcome class:

$greater = app(Welcome::class);
return $greater->driver('german')->great();

Although in this way, you use Laravel IOC container too. But if you want to be more convenient, combine this pattern with Laravel Facade feature. For instance, in our example, you should only add Facades prefix to the welcome class use keyword. The final code would be like this:

use Facades\App\Welcome; // <-- Laravel automatically would implement facade on the welcome class
  
Route::get('/', function () {
    return Welcome::driver('german')->great();
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1