Answers:
好的,我有两个大项目,在这些项目中,我对服务器的控制足以控制名称空间并依靠自动加载。
第一。自动加载很棒。不担心需求是一件相对好的事情。
这是我在一些项目中一直使用的装载机。首先检查以确保该类位于当前名称空间中,如果没有,则进行保释。从那里开始,只有一些字符串操作才能找到该类。
<?php
spl_autoload_register(__NAMESPACE__ . '\\autoload');
function autoload($cls)
{
$cls = ltrim($cls, '\\');
if(strpos($cls, __NAMESPACE__) !== 0)
return;
$cls = str_replace(__NAMESPACE__, '', $cls);
$path = PLUGIN_PATH_PATH . 'inc' .
str_replace('\\', DIRECTORY_SEPARATOR, $cls) . '.php';
require_once($path);
}
可以很容易地将其改编为无需命名空间使用。假设您统一为插件/主题的类添加前缀,则只需测试该前缀即可。然后在类名中使用下划线作为目录分隔符的占位符。如果您使用许多类,则可能需要使用某种类图自动加载器。
WordPress的hooks系统通过使用call_user_func
(和call_user_func_array
)进行工作,该函数将函数名称作为字符串,并在进行do_action
(和随后的call_user_func
)函数调用时调用它们。
使用名称空间,这意味着您需要将包含名称空间的标准函数名称传递给钩子。
<?php
namespace WPSE\SomeNameSpace;
add_filter('some_filter', 'WPSE\\SomeNameSpace\\the_function');
function the_function()
{
return 'did stuff';
}
__NAMESPACE__
如果要这样做,最好自由地使用魔术常数。
<?php
namespace WPSE\SomeNameSpace;
add_filter('some_filter', __NAMESPACE__ . '\\the_function');
function the_function()
{
return 'did stuff';
}
如果您总是将自己的知识投入课堂,那会更容易。一个类的标准创建实例和构造函数中的所有钩子都$this
可以正常工作。
<?php
namespace WPSE\SomeNameSpace;
new Plugin;
class Plugin
{
function __construct()
{
add_action('plugins_loaded', array($this, 'loaded'));
}
function loaded()
{
// this works!
}
}
如果您像我想使用的那样使用静态方法,则需要将完全限定的类名作为数组的第一个参数传递。这项工作很繁琐,因此您可以使用魔法__CLASS__
常数或get_class
。
<?php
namespace WPSE\SomeNameSpace;
Plugin::init();
class Plugin
{
public static function init()
{
add_action('plugins_loaded', array(__CLASS__, 'loaded'));
// OR: add_action('plugins_loaded', array(get_class(), 'loaded'));
}
public static function loaded()
{
// this works!
}
}
PHP的类名解析有些古怪。如果要使用核心WP类(WP_Widget
在下面的示例中),则必须提供use
语句。
use \WP_Widget;
class MyWidget extends WP_Widget
{
// ...
}
或者,您可以使用完全限定的类名-基本上只是在其前面加上反斜杠。
<?php
namespace WPSE\SomeNameSpace;
class MyWidget extends \WP_Widget
{
// ...
}
这是更通用的PHP,但是它使我感到不适,所以就在这里。
您可能需要定义经常使用的功能,例如插件的路径。除非您将命名空间显式传递给define的第一个参数,否则使用define语句会将其放置在根命名空间中。
<?php
namespace WPSE\SomeNameSpace;
// root namespace
define('WPSE_63668_PATH', plugin_dir_path(__FILE__));
// in the current namespace
define(__NAMESPACE__ . '\\PATH', plugin_dir_path(__FILE__));
您还可以在const
PHP 5.3 plus的文件根级别中使用关键字on。 consts
始终位于当前名称空间中,但不如define
调用灵活。
<?php
namespace WPSE\SomeNameSpace;
// in the current namespace
const MY_CONST = 1;
// this won't work!
const MY_PATH = plugin_dir_path(__FILE__);
请随时添加您可能有的其他提示!
这是2017年的答案。
自动加载很棒。命名空间很棒。
尽管您可以自己滚动它,但在2017年,使用宏伟而无处不在的Composer来满足您的PHP需求是最有意义的。Composer支持PSR-0和PSR-4自动加载,但自2014年以来已弃用前者,因此请使用PSR-4。它降低了目录的复杂性。
我们将每个插件/主题都保存在自己的Github存储库中,每个插件/主题都有各自的composer.json
文件和composer.lock
文件。
这是我们用于插件的目录结构。(我们实际上没有名为的插件awesome-plugin
,但应该。)
plugins/awesome-plugin/bootstrap.php
plugins/awesome-plugin/composer.json
plugins/awesome-plugin/composer.lock
plugins/awesome-plugin/awesome-plugin.php
plugins/awesome-plugin/src/*
plugins/awesome-plugin/vendor/autoload.php
plugins/awesome-plugin/vendor/*
如果提供适当的composer.json
文件,则Composer会在此处处理名称间隔和自动加载。
{
"name": "awesome-company/awesome-plugin",
"description": "Wordpress plugin for AwesomeCompany website, providing awesome functionality.",
"type": "wordpress-plugin",
"autoload": {
"psr-4": {
"AwesomeCompany\\Plugins\\AwesomePlugin\\": "src"
}
}
}
当您运行时composer install
,它将创建vendor
目录和vendor/autoload.php
文件,这将自动在src/
以及可能需要的所有其他库中加载所有以名称分隔的文件。
然后,在主插件文件(对于我们来说是awesome-plugin.php
)的顶部,插件元数据之后,您只需要:
// Composer autoloading.
require_once __DIR__ . '/vendor/autoload.php';
...
并非必需,但是我们从一开始就使用Bedrock Wordpress样板使用Composer。然后,我们可以使用Composer通过Composer组装所需的插件,包括您在上面编写的自己的插件。此外,多亏了WPackagist,您可以从Wordpress.org需要任何其他插件(请参见cool-theme
和示例cool-plugin
)。
{
"name": "awesome-company/awesome-website",
"type": "project",
"license": "proprietary",
"description": "WordPress boilerplate with modern development tools, easier configuration, and an improved folder structure",
"config": {
"preferred-install": "dist"
},
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
},
{ // Tells Composer to look for our proprietary Awesome Plugin here.
"url": "https://github.com/awesome-company/awesome-plugin.git",
"type": "git"
}
],
"require": {
"php": ">=5.5",
"awesome-company/awesome-plugin": "dev-production", // Our plugin!
"wpackagist-plugin/cool-plugin": "dev-trunk", // Someone else' plugin
"wpackagist-theme/cool-theme": "dev-trunk", // Someone else' theme
"composer/installers": "~1.2.0", // Bedrock default
"vlucas/phpdotenv": "^2.0.1", // Bedrock default
"johnpbloch/wordpress": "4.7.5", // Bedrock default
"oscarotero/env": "^1.0", // Bedrock default
"roots/wp-password-bcrypt": "1.0.0" // Bedrock default
},
"extra": {
// This is the magic that drops packages with the correct TYPE in the correct location.
"installer-paths": {
"web/app/mu-plugins/{$name}/": ["type:wordpress-muplugin"],
"web/app/plugins/{$name}/": ["type:wordpress-plugin"],
"web/app/themes/{$name}/": ["type:wordpress-theme"]
},
"wordpress-install-dir": "web/wp"
},
"scripts": {
"test": [
"vendor/bin/phpcs"
]
}
}
注意1:注释在JSON中不合法,但是为了更加清晰起见,我在上面的文件中添加了注释。
注意2:为简洁起见,我已将样板基岩文件切掉了一些。
注意3:这就是为什么type
第一个composer.json
文件中的字段很重要的原因。Composer会自动将其拖放到web/app/plugins
目录中。
我使用自动加载功能(因为我的插件有很多类,部分是因为它包含Twig),从来没有引起我注意的问题(插件安装> 20,000次)。
如果您有信心永远不需要使用不支持名称空间的php安装,那么就可以了(大约70%的当前wordpress博客不支持名称空间)。注意事项:
我似乎记得,在常规php中,名称空间不区分大小写,但是在iis上使用fastcgi php时-如果在Linux上进行测试并且没有发现流氓的小写字母,这会引起一些麻烦。
同样,即使您确定当前正在开发的代码仅在> 5.3.0上使用,您也将无法在不那么奢侈的项目中重用任何代码-这就是我没有这样做的主要原因内部项目上使用的名称空间。我发现,命名空间实在不加是当用具有去除对他们的依赖的可能比较头疼了。