I'm putting together a simple application container for learning purposes, and I would like to hear how you see this code. The application is the main class that will contain services, configuration and other related stuff.I have identified 3 position where I can't decide on the design:Each application should be supplied with configuration array. The configuration will be loaded automatically, so some class has to deal with it. Does Kernel class is the right place to put it? The Kernel class is intended to contain some common functions, like getRootPath(). Does it starts to violate SRP in this case?   Does getType() look like the right way to define type of application? Should i make it abstract or provide some default type in parent class?  Overall, does Kernel class fits the purpose of creating application instances and supplying required configuration and calling ready() on application?namespace App;interface Executable {    public function run();    public function ready();}abstract class Application implements Executable {    const TYPE_WEB = 'web';    const TYPE_CLI = 'cli';    /**    * Application name    * @var string    */    protected $name = '';    /**    * Application configuration    * @var array    */    protected $config = [];    public function __construct($name, array $config=[]) {        $this -> name = $name;        $this -> config = $config;    }    public function ready() {        // Application is ready, register services here...    }    public function run() {        // Execute application lifecycle    }}class WebApplication extends Application {    public function getType() {        return self::TYPE_WEB;    }}class ConsoleApplication extends Application {    public function getType() {        return self::TYPE_CLI;    }}abstract class Kernel {    /**    * Instantiated applications    * @var Executable[]    */    private static $apps = [];    /**    * Creates new application    * @param string $name Application name    * @param string $type Application class    */    public static function createApp($name, $type) {        /* Some validations skipped */        $app = self::$apps[$name] = new $type($name, self::loadConfiguration($name));        $app -> ready();        return $app;    }    private static function loadConfiguration($name) {        /* Load configuration from files and from multiple places */        return [            'key' => 'value'        ];    }    public static function getRootPath() {        // Return path to document root    }}/**************/App\Kernel::createApp('test', 'WebApplication') -> run();
Application container design
php;object oriented
Some opinionated advice:I don't see why having two separate class, so I merge Kernel into App and rename it AppKernel. Then, I removed the ready method to replace it by the create from Kernel.You don't need the getType function since your classes already define a typeI don't really understand why you want to keep a reference to your application's instances, so I remove it.For me you should load the configuration from the outside with a dedicated configuration object.EDIT: I added a method to create singleton application, I think this method will work but I am not 100% sure, so try it before.All this transformation lead to something like this: <?phpnamespace App;interface Executable{    public function run();    public function ready();}class Configuration{    public static function load() {        return [            'key' => 'value'        ];    }}abstract class AppKernel implements Executable{    /**     * Application name     * @var string     */    protected $name = '';    private static $instances = [];    /**     * Application configuration     * @var array     */    protected $config = [];    protected function __construct($name, Configuration $config)    {        $this->name = $name;        $this->config = $config;    }    public static function create($name, Configuration $config)    {        if(!isset(static::$instance[$name]))           static::$instance[$name] = new static($name, $config);        return static::$instance[$name];    }    public function run()    {    }}class WebApplication extends AppKernel {}class ConsoleApplication extends AppKernel {}ConsoleApplication::create('name', configuration::load())->run();