Yii uses path aliases extensively. A path alias is associated with a directory or file path. It is specified in dot syntax, similar to that of widely adopted namespace format:
RootAlias.path.to.target
where RootAlias
is the alias of some existing directory.
By using YiiBase::getPathOfAlias(), an alias can be translated to its
corresponding path. For example, system.web.CController
would be
translated as yii/framework/web/CController
.
We can also use YiiBase::setPathOfAlias() to define new root path aliases.
For convenience, Yii predefines the following root aliases:
system
: refers to the Yii framework directory;zii
: refers to the Zii library directory;application
: refers to the application's base directory;webroot
: refers to the directory containing the entry script file.ext
: refers to the directory containing all third-party extensions.Additionally, if an application uses modules, each module will have a predefined
root alias that has the same name as the module ID and refers to the module's base path. For example,
if an application uses a module whose ID is users
, a root alias named users
will be predefined.
Using aliases, it is very convenient to include the definition of a class. For example, if we want to include the CController class, we can call the following:
Yii::import('system.web.CController');
The import method differs from include
and require
in that it is more efficient. The class definition being imported is
actually not included until it is referenced for the first time (implemented
via PHP autoloading mechanism). Importing the same namespace multiple times
is also much faster than include_once
and require_once
. Note that importing
a directory does not import any of its subdirectories.
Tip: When referring to a class defined by the Yii framework, we do not need to import or include it. All core Yii classes are pre-imported.
Starting from version 1.1.5, Yii allows user classes to be pre-imported via a class mapping mechanism that is also used by core Yii classes. Pre-imported classes can be used anywhere in a Yii application without being explicitly imported or included. This feature is most useful for a framework or library that is built on top of Yii.
To pre-import a set of classes, the following code must be executed before CWebApplication::run() is invoked:
Yii::$classMap=array(
'ClassName1' => 'path/to/ClassName1.php',
'ClassName2' => 'path/to/ClassName2.php',
......
);
We can also use the following syntax to import a whole directory so that the class files under the directory can be automatically included when needed.
Yii::import('system.web.*');
Besides import, aliases are also used in many other places to refer to classes. For example, an alias can be passed to Yii::createComponent() to create an instance of the corresponding class, even if the class file was not included previously.
A namespace refers to a logical grouping of some class names so that they can be differentiated from other class names even if their names are the same. Do not confuse path alias with namespace. A path alias is merely a convenient way of naming a file or directory. It has nothing to do with a namespace.
Tip: Because PHP prior to 5.3.0 does not support namespace intrinsically, you cannot create instances of two classes who have the same name but with different definitions. For this reason, all Yii framework classes are prefixed with a letter 'C' (meaning 'class') so that they can be differentiated from user-defined classes. It is recommended that the prefix 'C' be reserved for Yii framework use only, and user-defined classes be prefixed with other letters.
A namespaced class refers to a class declared within a non-global namespace.
For example, the application\components\GoogleMap
class is declared within
the namespace application\components
. Using namespaced classes requires PHP 5.3.0 or above.
Starting from version 1.1.5, it is possible to use a namespaced class without
including it explicitly. For example, we can create a new instance of
application\components\GoogleMap
without including the corresponding class file
explicitly. This is made possible with the enhanced Yii class autoloading mechanism.
In order to be able to autoload a namespaced class, the namespace must be named in
a way similar to naming a path alias. For example, the class application\components\GoogleMap
must be stored in a file that can be aliased as application.components.GoogleMap
.
So to use custom namespace starting with, for example, \mynamespace
where
classes are located at /var/www/common/mynamespace/
, the only thing you
should do is to define a path alias like the following:
Yii::setPathOfAlias('mynamespace', '/var/www/common/mynamespace/');
By default Yii uses controllers from the global namespace. These classes are
located under protected/controllers
. You can change this behavior in two
different ways: using controllerMap
and using controllerNamespace
. The former
allows you to use controllers from various namespaces. The latter requires less
configuration while setting a common namespace for all controllers.
controllerMap
The best way to change controller map is to use the configuration file
(protected/config/main.php
):
// adding "mynamespace" namespace
Yii::setPathOfAlias('mynamespace', '/var/www/common/mynamespace/');
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'My Web Application',
'controllerMap' => array(
'test' => '\mynamespace\controllers\TestController',
),
When user tries to load any of the controllers defined in controllerMap
,
Yii loads the specified classes, bypassing the normal controller loading method.
In case of test
Yii will load the namespaced class
\mynamespace\controllers\TestController
located at
/var/www/common/mynamespace/controllers/TestController.php
.
Note that controller code should be properly namespaced:
// define namespace:
namespace mynamespace\controllers;
// since class is now under namespace, global namespace
// should be referenced explicitly using "\":
class TestController extends \CController
{
public function actionIndex()
{
echo 'This is TestController from \mynamespace\controllers';
}
}
controllerNamespace
Since application is the module itself, you can use controllerNamespace
property
in the same way as described in "Namespaced Modules" below.
Sometimes it's useful to namespace the whole module. For example, if you
want to put testmodule
under \mynamespace\modules\testmodule
pointing to
/var/www/common/mynamespace/modules/testmodule
you should first create the following
file structure:
/var/www/common/mynamespace/modules testmodule controllers DefaultController.php views default index.php TestmoduleModule.php
index.php
view is the same as in regular module. TestmoduleModule.php
and
DefaultController.php
are namespaced.
TestmoduleModule.php
:
// define namespace:
namespace mynamespace\modules\testmodule;
// since class is now under namespace, global namespace
// should be referenced explicitly using "\":
class TestmoduleModule extends \CWebModule
{
// setting non-global controllers namespace (also can be done via config)
public $controllerNamespace = '\mynamespace\modules\testmodule\controllers';
// usual module code
}
DefaultController.php
:
// define namespace: namespace mynamespace\modules\testmodule\controllers; // since class is now under namespace, global namespace // should be referenced explicitly using "\": class DefaultController extends \Controller { public function actionIndex() { $this->render('index'); } }
Now the only thing left is to add our module to the application. The best way
to do it is to specify it in the application config file (protected/config/main.php
):
// adding "mynamespace" namespace
Yii::setPathOfAlias('mynamespace', '/var/www/common/mynamespace/');
return array(
'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
'name'=>'My Web Application',
'modules'=>array(
'testmodule' => array(
'class' => '\mynamespace\modules\testmodule\TestModuleModule',
),
),
Found a typo or you think this page needs improvement?
Edit it on github !
Namespaces in a nutshell
Namespaces in php are like directory paths in console (bash, dos etc)
When you use
namespace
php keyword like thisnamespace a\random\namespace; class Foo { static function bar(){} }
is like executing
cd a\specific\directory
except that the namespace is created if not exists.Now everything follows is belonging to that namespace. This means that if you want to instantiate, extend or call a static method from eg
foo
class on another namespace you have to//The leading backslash '\' here denotes the global namespace that //is the root folder or C:\ counterpart from console environment $baz= new \a\random\namespace\Foo; class Fighter extends \a\random\namespace\Foo {} \a\random\namespace\Foo::bar();
Yii imports a very intuitive convention here that the namespace structure (if implemented) should be reflected on the physical directory structure and additionally makes its Path Alias convenience available for that purpose.
Please be my guest to follow these steps:
protected\components
and create a folderfoo
Controller.php
infoo
folder and open it with an editorController
class declaration import this:namespace application\components\foo; class Controller extends \CController //Note the leading backslash here
protected\controllers\SiteController.php
for editingSiteController
class declaration with thisclass SiteController extends \application\components\foo\Controller
As you will see, your new web app still working fine and
application
path alias will point properly atprotected
folder.You can find more about php namespaces here
Enjoy coding :>
Using Yii::app() with namespaces
When using namespaces, you might see an error about the application not being able to find "Yii.php". If you run into this, there are 2 solutions.
1) Instead of
namespace application\components\foo; class Controller extends \CController { public function actionIndex() { $request = Yii::app()->getRequest(); //Error: could not find Yii.php }
Tell PHP you want it to look within the Yii namespace so it knows where to find any Yii objects...
namespace application\components\foo; use Yii; class Controller extends \CController { public function actionIndex() { $request = Yii::app()->getRequest(); //doesn't throw an error }
2) Change all instances of
to
Though ideally you would use the first solution.
Module alias not always defined
Normally, a module alias is immediately available in your application. But if you declare your module like this:
'modules' => array( 'bar' => array( 'class' => 'vendor.test.bar.BarModule' ), ),
The
bar
alias is not available until the module has been instantiated (Yii::app()->getModule('bar')
). This limitation is not likely to be fixed.Signup or Login in order to comment.