Questions about Yii2 yii\ web\ Application

  • index.php
$application = new yii\web\Application($config);
$application->run();
  • yii\ base\ Application::__construct ()
public function __construct($config = [])
{
    Yii::$app = $this;
    static::setInstance($this);
    $this->state = self::STATE_BEGIN;

    $this->preInit($config);
    $this->registerErrorHandler($config);
    
    Component::__construct($config);

    var_dump($this);die; //  $this
}
  • output result
object(yii\web\Application)-sharp5 (33) {
    ......
    ["_modules":"yii\base\Module":private]=>
        array(3) {
            ["debug"]=> object(yii\debug\Module)-sharp33 (28) {
                ......
            }
            ["gii"]=> object(yii\gii\Module)-sharp113 (21) {
                ......
            }
            ...
        }
    ["_definitions":"yii\di\ServiceLocator":private]=>
        array(24) {
            ["errorHandler"]=> .....
            ["request"]=> ......
            ["log"]=> ......
            ......
        }
    ......
}

question: object (yii\ web\ Application) where are the attributes in _ modules and _ definitions assigned?

Mar.11,2021

first of all, your $config array must contain the following elements:

$config = [
    //others
    'modules' => [
        'debug' => [
            'class' => 'yii\debug\Module',
        ], 
        'gii'   => [
            'class' => 'yii\gii\Module',
        ];
    ],
    //others
]

explain the inheritance relationship here:

class yii\base\Application extends yii\base\Module

class yii\base\Module extends yii\di\ServiceLocator

class yii\di\ServiceLocator extends yii\base\Component

class yii\base\Component extends yii\base\Object
< hr >
  • yiibaseApplication::__construct () method comments
public function __construct($config = [])
{
    Yii::$app = $this;
    //\yii\base\ApplicationYii::$app->loadedModules
    static::setInstance($this);

    $this->state = self::STATE_BEGIN;

    // :
    $this->preInit($config);

    //
    $this->registerErrorHandler($config);

    //  __construct
    // Component__construct
    //  `yii\base\Object__construct($config)`
    Component::__construct($config);
}

in the above method Component::__construct ($config) will call yii\ base\ Object::__construct () method

  • yiibaseObject::__construct () method comments
public function __construct($config = [])
{
    if (!empty($config)) {
        // Object
        // Object
        // yii\web\Application
        Yii::configure($this, $config);
    }
    $this->init();
}
< hr >

1. The following is just to explain where 'components' = > [' log' = > [.]] comes from. If you don't care, you can go straight to the second step.

  • first look at $this- > preInit ($config); , that is, yii\ base\ Application::preInit (& $config)
public function preInit(&$config)
{
    //others...
    
    // merge core components with custom components
    // 
    foreach ($this->coreComponents() as $id => $component) {
        if (!isset($config['components'][$id])) {
            // 
            $config['components'][$id] = $component;
        } elseif (is_array($config['components'][$id]) && !isset($config['components'][$id]['class'])) {
            //  'class'class
            $config['components'][$id]['class'] = $component['class'];
        }
    }
}

/**
 * Returns the configuration of core application components.
 * 
 * @see set()
 */
public function coreComponents()
{
    return [
        // 
        'log' => ['class' => 'yii\log\Dispatcher'],
        
        //others...
    ];
}
  • after $this- > preInit ($config); , we get $config
$config = [
    'modules' => [
        'debug' => [
            'class' => 'yii\debug\Module',
        ], 
        'gii'   => [
            'class' => 'yii\gii\Module',
        ];
    ],
    'components' => [
        'log'   => [
            'class' => 'yii\\log\\Dispatcher',
        ],
        
        //others...
    ]
    //others...
]
< hr > < hr >

the above is just to explain 'components' = > [' log' = > [.]] where it comes from

2. The key point is here

  • yii\ base\ Object::__construct ($config = []) Yii::configure ($this, $config); )
public static function configure($object, $properties)
{
    // 
    foreach ($properties as $name => $value) {
        $object->$name = $value;
    }
    return $object;
}
  • here we need to cooperate with yii\ base\ Object::__set ($name, $value)
/**
 * 
 *
 * Do not call this method directly as it is a PHP magic method that
 * will be implicitly called when executing `$object->property = $value;`.
 * PHP `$object->property = $value;` 
 */
public function __set($name, $value)
{
    // setter
    // phpsetproperty()  setProperty()
    $setter = 'set' . $name;
    if (method_exists($this, $setter)) {
        // setter
        $this->$setter($value);
    } elseif (method_exists($this, 'get' . $name)) {
        // gettersetter 
        throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
    } else {
        throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
    }
}

$object in the current context, we can think of it as yii\ base\ Application $app

.
  • when traversing to:
$app->modules =  [
    'debug' => [
        'class' => 'yii\debug\Module',
    ], 
    'gii'   => [
        'class' => 'yii\gii\Module',
    ];
]

the yii\ base\ Module::setModules ($modules) method will be called here

public function setModules($modules)
{
    foreach ($modules as $id => $module) {
        $this->_modules[$id] = $module;
    }
}

so you have

in question.
["_modules":"yii\base\Module":private]=>
    array(3) {
        ["debug"]=> object(yii\debug\Module)-sharp33 (28) {
            ......
        }
        ["gii"]=> object(yii\gii\Module)-sharp113 (21) {
            ......
        }
        ...
    }
  • the same thing, when traversing to:
$app->components =  [
    'log'   => [
        'class' => 'yii\\log\\Dispatcher',
    ],
]
  • the yii\ di\ ServiceLocator::setComponents ($components) method
will be called here.
public function setComponents($components)
{
    foreach ($components as $id => $component) {
        $this->set($id, $component);
    }
}

public function set($id, $definition)
{
    // others ...

    if (is_object($definition) || is_callable($definition, true)) {
        // an object, a class name, or a PHP callable
        $this->_definitions[$id] = $definition;
    } elseif (is_array($definition)) {
        //  class 
        // a configuration array
        if (isset($definition['class'])) {
            //  $_definitions 
            $this->_definitions[$id] = $definition;
        } else {
            throw new InvalidConfigException("The configuration for the \"$id\" component must contain a \"class\" element.");
        }
    } else {
        throw new InvalidConfigException("Unexpected configuration type for the \"$id\" component: " . gettype($definition));
    }
}

so you have

in question.
["_definitions":"yii\di\ServiceLocator":private]=>
        array(24) {
            ["errorHandler"]=> .....
            ["request"]=> ......
            ["log"]=> ......
            ......
        }
Menu