有没有人在插件或主题中使用过自动加载和/或PHP名称空间?

使用它们的想法?有什么伤害吗陷阱?

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

#1 楼

好的,我有两个大项目,在这些项目中,我对服务器的控制足以控制名称空间并依靠自动加载。

首先。自动加载很棒。不用担心需求是相对不错的事情。

这是我在一些项目中一直使用的装载机。首先检查以确保该类位于当前名称空间中,如果没有,则进行保释。从那里开始,仅需进行一些字符串操作即可找到该类。

<?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!
    }
}


使用核心类有点古怪。如果要使用核心WP类(在下面的示例中为WP_Widget),则必须提供use语句。




use \WP_Widget;

class MyWidget extends WP_Widget
{
   // ...
}


或者您可以使用完全限定的类名-基本上只是在其前面加上反斜杠即可。 br />
定义

这是更通用的PHP,但是它让我很吃力,所以就在这里。通常,例如插件的路径。除非您将命名空间明确传递给define的第一个参数,否则使用define语句会将其放置在根名称空间中。

PHP 5.3 plus的文件级别。 const始终位于当前名称空间中,但不如consts调用灵活。

<?php
namespace WPSE\SomeNameSpace;

class MyWidget extends \WP_Widget
{
   // ...
}


请随时添加您可能有的其他提示! >

#2 楼

这是2017年的答案。

自动加载功能很棒。 Namespacing很棒。

虽然可以自己滚动,但在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-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目录。

评论


感谢您的回答,非常有帮助!但是我对您所指的“ bootstrap.php”很好奇。它包含什么? :)

– INT
18-09-22在20:15

在我的大多数项目中,无论是否在WP中,都有bootstrap.php文件都是我的风格。我的引导程序通常只检查设置和环境变量。它的主要目的是确保我的插件始终具有运行所需的功能,而不管它是从WP内部运行还是作为独立的PHP应用程序运行。

– haz
18-09-23在22:43

您好,我在哪里运行“ composer install”?

–列宁·萨帕塔(Lenin Zapata)
4月27日下午5:13

@LeninZapata您应该在带有composer.json文件的目录中运行composer install。例如,如果克隆Bedrock(github.com/roots/bedrock),则进入您的bedrock目录并在其中运行它。

– haz
5月6日6:43

#3 楼

我使用自动加载功能(因为我的插件有很多类,部分是因为它包含Twig),所以从来没有引起我注意的问题(插件安装> 20,000次)。

如果您有信心的话永远都不需要使用不支持名称空间的php安装,那就可以了(大约70%的当前wordpress博客不支持名称空间)。需要注意的几件事:

我似乎记得常规php中的名称空间不区分大小写,但是在iis上使用fastcgi php时-如果在linux上进行测试并且没有发现,这会引起一些麻烦

即使您确定当前正在开发的代码仅在> 5.3.0上使用,您也将无法在没有该代码的项目中重用任何代码如此奢侈-这就是为什么我没有在内部项目上使用名称空间的主要原因。我发现,与不得不删除对它们的依赖关系可能带来的麻烦相比,名称空间确实没有添加太多。