WordPress插件和主题中的自动加载和命名空间:它能工作吗?

时间:2012-08-30 作者:chrisguitarguy

有人用过吗autoloading 插件或主题中的和/或PHP命名空间?

关于使用它们的想法?有什么害处吗?陷阱?

注意:名称空间仅适用于PHP 5.3以上版本。对于这个问题,假设您知道将要处理的服务器具有PHP 5.3或更高版本

3 个回复
最合适的回答,由SO网友:chrisguitarguy 整理而成

好的,我有两个大项目,在这两个项目中,我对服务器的控制足够多,可以使用名称空间并依赖于自动加载。

首先。自动加载非常棒。不担心需求是一件相对较好的事情。

这是我在几个项目中使用的加载程序。首先检查以确保该类位于当前命名空间中,如果不在,则将其清除。从这里开始,只需一些字符串操作即可找到类。

<?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的挂钩系统通过使用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文件根级别中的关键字。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__);

Please feel free to add any other tips you might have!

SO网友:haz

以下是2017年的答案。

自动加载非常棒。命名空间太棒了。

虽然你可以自己动手,但在2017年,使用华丽且无处不在的Composer 处理您的PHP需求。Composer同时支持PSR-0PSR-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提供任何其他插件。组织(参见示例cool-themecool-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 目录

SO网友:Daniel Chatfield

我使用自动加载(因为我的插件有很多类,部分原因是它包含了细枝),从来没有引起过我的注意(插件安装次数超过20000次)。

如果您确信永远不需要使用不支持名称空间的php安装,那么您也很好(目前约70%的wordpress博客不支持名称空间)。需要注意的几点:

我似乎记得,在普通php中,名称空间不区分大小写,但在iis上使用fastcgi php时,名称空间是区分大小写的——如果您在linux上进行测试,并且没有发现恶意的小写字母,这会引起一些头痛。

此外,即使您确信当前正在开发的代码将仅用于>5.3.0,您也无法将任何代码重用到没有这种奢华的项目中-这就是我没有在内部项目中使用名称空间的主要原因。我发现,与必须消除对名称空间的依赖这一可能令人头痛的问题相比,名称空间真的没有增加多少。

结束

相关推荐