Вопрос: Как работает Yii::app()?

Лучший ответ: 1. Инициализация Yii::app()
Смотри, в файле www/index.php такие строки1. $config = APP_PATH . '/protected/config/main.php';
2. $app = \Yii::createWebApplication($config); // @var CWebApplication $app
3. $app->run();
При отработке строки 2 выполняется код1. class YiiBase {
2. {
3.     // ... другой код
4. 
5.     public static function createWebApplication($config=null)
6.     {
7.         return self::createApplication('CWebApplication',$config);
8.     }
9.
10.    public static function createApplication($class,$config=null)
11.    {
12.        return new $class($config);
13.    }
14. }
В строке 12 с учётом динамического связывания выполняется return new CWebApplication($config);
Если пройти по родительским классам, то можно найти, что class CWebApplication extends CApplication ...
и далее1. abstract class CApplication extends CModule
2. {
3.     // ... другой код
4. 
5.     public function __construct($config=null)
6.     {
7.         Yii::setApplication($this);
8.         // ... и другой код
9.     }
10. }
В строке 7 вызывается Yii::setApplication($this);, а если посмотреть класс Yii и его родителя YiiBase, то можно увидеть как в итоге инициализируется переменная для конструкции Yii::app()class Yii extends YiiBase { }class YiiBase {
{
    private static $_app;
    public static function setApplication($app) // тут определяется значение self::$_app для Yii::app()
    {
        if(self::$_app===null || $app===null)
            self::$_app=$app;
        else
            throw new CException(Yii::t('yii','Yii application can only be created once.'));
    }
    public static function app() // тут можно прочитать значение self::$_app через Yii::app()
    {
        return self::$_app;
    }
}
Теперь понятно, что при инициализации сущности типа CWebApplication эта сущность установилась в приватную переменную YiiBase::$_app, которая доступна через вызов Yii::app()
Это была инициализация
2. Использование Yii::app()->module или Yii::app()->component
Ещё раз посмотри на класс CApplicationabstract class CApplication extends CModule
{
    public function __construct($config=null)
    {
        Yii::setApplication($this);

        // ... другой код

        $this->configure($config);

        // ... другой код
    }
}
В методе configure($config) происходит подготовка данных, которые понадобятся позже для таких вызовов как (к примеру) Yii::app()->db
Давай посмотрим на класс Module, в котором и реализуется логика таких вызововabstract class CModule extends CComponent
{
    public function configure($config) // сохранить всё что передали по переменным
    {
        if(is_array($config))
        {
            foreach($config as $key=>$value)
                $this->$key=$value;
        }
    }

    public function __get($name) // если кто-то пытается вызвать несуществующее свойство, например Yii::app()->db
    {
        if($this->hasComponent($name)) // проверить что есть настройки или готовая сущность компоненты
            return $this->getComponent($name); // вернуть сущность компоненты
        else
            return parent::__get($name);
    }

    public function hasComponent($id) // проверить что есть настройки или готовая сущность компоненты
    {
        return isset($this->_components[$id]) || isset($this->_componentConfig[$id]);
    }

    public function getComponent($id,$createIfNull=true) // вернуть сущность компоненты
    {
        if(isset($this->_components[$id])) // если есть готовая сущность компоненты, вернуть её
            return $this->_components[$id];
        elseif(isset($this->_componentConfig[$id]) && $createIfNull)
        {
            $config=$this->_componentConfig[$id];
            if(!isset($config['enabled']) || $config['enabled'])
            {
                unset($config['enabled']);
                $component=Yii::createComponent($config); // создать новую сущность компоненты
                $component->init();
                return $this->_components[$id]=$component; // сохранить и вернуть её
            }
        }
    }
}
Попробуем расшифровать вызов Yii::app()->db
Как я уже показал, Yii::app() - это сущность типа CWebApplication, а у неё нет публичного свойства $db, поэтому PHP вызывает магический метод __get() из базового класса CModule. (Посмотри в документации "магические методы")
Итак, свойства CWebApplication->db не существует и вызывается CModule->__get('db'), далее код считает, что, возможно производится вызов компоненты.
Метод CModule->hasComponent('db') проверяет, что ранее были заданы какие-то настройки указанной через файл конфигурации protected/config/main.php или иным способом. Если так, то то вызывается CModule->getComponent('db', ...), который вызывает Yii::createComponent($config), где $config - это найденные настройки указанной компоненты, например, параметры соединения с базой данных для компоненты db
Посмотрим, что делает Yii::createComponent($config)class YiiBase
{
    public static function createComponent($config)
    {
        // посмотри сам, тут интересно
    }
}
Cложный метод. Суть его в инстанциировании новой сущности какого-то класса, 5 или 6 способов. Дело в том, что этот метод CModule::createComponent() может быть вызван откуда угодно и у него куча вариантов передачи параметров.
Итак, CModule::createComponent() создал и вернул новую сущность. И на выходе из метода CModule::getComponent() полученная сущность записывается в массив CModule->_components под именем 'db'.
Все последующие вызовы Yii::app()->db будут проверять наличие инстанциинованной сущности в массиве CModule->_components['db'] и использовать его, если он там найден
Заключение:
Вызов Yii::app()->db
А. Динамически инициализирует компоненту, по мере необходимости
Б. Настраивает её данными, которые в частновти можно определить через файл конфигурации protected/config/main.php
В. Инициализируют компоненту только один раз за цикл работы PHP приложения
Надеюсь я понятно изложил механизм ленивой инициализации компонент

Худший ответ: Через конфиг. Указываешь имя компонента, и в массиве передаешь ему имя класса, а также список предопределённых параметров. Что-то типа'components' => [
  'someService => [
    'class' => 'path\to\class\ClassName',
    'param1' => 'one',
    'param2' => 'two',
  ]
]
Соответственно, в классе ClassName у тебя должны быть поля public $param1 и $param2, куда просаживаются значения из конфига.
www.bsourcecode.com/yiiframework2/how-to-create-cu...
Там есть ещё некоторая разница между первым и вторым Yii в вызове компонента. В первом Yii::app(), а во втором Yii::$app