命名空間

FuelPHP,做为一个 PHP 5.3+ 框架,很大程度依賴命名空間來分隔框架和你的应用程序的不同元件, to make the code as portable as possible, and to prevent any collisons in class names when you're moving bits of your application around.

By default, the exception to this is your main application code, which resides in APPPATH/classes. All main application classes are defined in the global namespace (they do not have a namespace set), and use the cascading file system to create unique classnames.

While this makes it easier for the novice to start using the FuelPHP framework, it will create more complex class names, and it will make those classes less portable or interchangable.

为你的控制器加上命名空間

As mentioned in the introduction, by default controllers are created in the APPPATH/classes/controller folder, and are prefixed with Controller_. This prefix is defined in your APPPATH/config/config.php configuration file (and if not this is the default), but can be changed if you want to namespace your controllers, or if you want to move them to a different folder structure.

Lets move the example given above to the Controller namespace. You tell FuelPHP that you've done this by setting the config setting controller_prefix from 'Controller_' to 'Controller\\' in your app's config.php file.

namespace Controller;

class Example extends \Controller
{
	public function action_index()
	{
		// 一些程式码
	}
}

Once you have enabled namespacing for your controllers, ALL your controller classes need to be namespaced! This means a controller in a module called Mymodule will look like this:

namespace Mymodule\Controller;

class Example extends \Controller
{
	public function action_index()
	{
		// 一些程式码
	}
}

Namespacing your controllers is completely transparent for your application, you can implement it without altering anything else. You can even mix-and-match namespacing and the cascading filesystem, and create a controller like \Controller\Admin\User_Groups which is defined in APPPATH/classes/controller/admin/user/groups.php.

Note that now that your controller lives in a namespace, you have to prefix all global classes (like "Controller" in the example) with a backslash, since it needs to be loaded from the global namespace. Alternative, you can use the 'use' keyword to import classes into the current namespace.

为你的模型加上命名空間

你可以立即開始为你的模型加上命名空間,不需要額外的配置。

namespace Model;

class Example extends \Orm\Model
{
	// 一些程式码
}

或在一个模組中:

namespace Mymodule\Model;

class Example extends \Model_Crud
{
	// 一些程式码
}

然後你可以在你的控制器中像这樣存取模型:

// the ORM model created above
$orm = \Model\Example::forge();

// the module crud model created above
$crud = \Mymodule\Model\Example::forge();

为你的表现控件加上命名空間

Since there is no configuration for the Presenter prefix, namespacing your presenters is a bit more complicated. It requires an extension of the Presenter class in your app. Create the following class:

// 位於 APPPATH/classes/presenter.php 的档案
class Presenter extends \Fuel\Core\Presenter
{
	// 命名空間前綴
	protected static $ns_prefix = 'Presenter\\';
}

And inform the framework you have extended the class by adding this to your APPPATH/bootstrap.php:

// add our presenter override
Autoloader::add_classes(array(
	'Presenter' => APPPATH.'classes/presenter.php',
));

Make sure you add it before the Autoloader is registered!

Once you have made this change, you can define your Presenters like so:

// 位於 APPPATH/classes/presenter/users/group.php 的档案
namespace Presenter\Admin\Users;

class Group
{
	public function view()
	{
		// your presenter code
	}
}

为其他类別加上命名空間

Any other class in the classes folder can be namespaced without problems, as long as the fully namespaced name of class can be mapped to the file which defines the class:

// 位於 APPPATH/classes/admin/users/group.php 的档案
namespace Admin\Users;

class Group
{
	// 一些程式码
}

// alternative for the same file and class
namespace Admin;

class Users_Group
{
	// 一些程式码
}

// or even old style without namespace
class Admin_Users_Group
{
	// 一些程式码
}

Caveats

Do not mix different naming styles for the same class

Although you can mix-and-match namespaces and underscores to construct your class names, you can not mix-and-match it's usage. If you have defined a class \Admin\Users\Group, using \Admin\Users_Group::method(); will load the correct file (since it maps correctly to the right file), but the autoloader will throw an exception because the expected \Admin\Users_Group class is not defined in that file.

So it is best to decide on a naming convention for your applications, and stick to it!

Class name collisions

When executing a Request, modules have precedence over the main app. This has some implications as to the names and namespaces you can use in your app, in relation to your module.

Say you have a module called Admin, then all classes in that module will be defined in a namespace that starts with \Admin. If at the same time you have classes in APPPATH/classes/admin, like in the example above, then
- those app classes will always work as long as the module isn't loaded.
- if the module is loaded, a module class with the same name has precedence, the app class can never be loaded.

Similarly, if you have a app Controller called Controller_Admin_Users, and you have a module called Admin, you can never have a URL Request load that app controller, since the Framework will look for that controller in the module based on the admin prefix.