Tự động tải và không gian tên trong Plugin & Chủ đề của WordPress: Nó có thể hoạt động không?


70

Có ai đã sử dụng tự động tải và / hoặc không gian tên PHP trong một plugin hoặc chủ đề chưa?

Suy nghĩ về việc sử dụng chúng? Có hại gì không? Cạm bẫy?

Lưu ý: không gian tên chỉ là PHP 5.3+. Giả sử, đối với câu hỏi này, bạn biết rằng bạn sẽ xử lý các máy chủ mà bạn biết có PHP 5.3 trở lên.

Câu trả lời:


88

Được rồi, tôi đã có hai dự án lớn, nơi tôi đã kiểm soát máy chủ đủ để không gian tên và dựa vào tự động tải.

Đầu tiên lên. Tự động tải là tuyệt vời. Không phải lo lắng về yêu cầu là một điều tương đối tốt.

Đây là một trình tải tôi đã sử dụng cho một vài dự án. Kiểm tra để chắc chắn rằng lớp nằm trong không gian tên hiện tại trước, sau đó bảo lãnh nếu không. Từ đó, chỉ cần một số thao tác chuỗi để tìm lớp.

<?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);
}

Người ta có thể dễ dàng điều chỉnh nó để sử dụng mà không cần không gian tên. Giả sử bạn có tiền tố các lớp / chủ đề của plugin một cách thống nhất, bạn chỉ có thể kiểm tra tiền tố đó. Sau đó sử dụng dấu gạch dưới trong tên lớp để làm chỗ dành cho các dấu tách thư mục. Nếu bạn đang sử dụng nhiều lớp, có thể bạn sẽ muốn sử dụng một số loại trình tải tự động lớp.

Không gian tên và móc

Hệ thống hook của WordPress hoạt động bằng cách sử dụng call_user_func(và call_user_func_array), lấy tên hàm làm chuỗi và gọi chúng khi cuộc gọi hàm do_action(và sau đó call_user_func) được thực hiện.

Với các không gian tên, điều đó có nghĩa là bạn sẽ cần chuyển các tên hàm đủ điều kiện bao gồm không gian tên thành các móc.

<?php
namespace WPSE\SomeNameSpace;

add_filter('some_filter', 'WPSE\\SomeNameSpace\\the_function');
function the_function()
{
   return 'did stuff';
}

Có lẽ sẽ tốt hơn nếu sử dụng __NAMESPACE__phép thuật tự do liên tục nếu bạn muốn làm điều này.

<?php
namespace WPSE\SomeNameSpace;

add_filter('some_filter', __NAMESPACE__ . '\\the_function');
function the_function()
{
   return 'did stuff';
}

Nếu bạn luôn đặt móc của mình vào các lớp học, điều đó sẽ dễ dàng hơn. Ví dụ tạo tiêu chuẩn của một lớp và tất cả các hook trong hàm tạo có $thishoạt động tốt.

<?php
namespace WPSE\SomeNameSpace;

new Plugin;

class Plugin
{
    function __construct()
    {
        add_action('plugins_loaded', array($this, 'loaded'));
    }

    function loaded()
    {
        // this works!
    }
}

Nếu bạn sử dụng các phương thức tĩnh như tôi muốn làm, bạn sẽ cần phải chuyển tên lớp đủ điều kiện làm đối số đầu tiên của mảng. Đó là rất nhiều công việc, vì vậy bạn chỉ cần sử dụng __CLASS__hằng số ma thuật hoặc 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!
    }
}

Sử dụng các lớp lõi

Độ phân giải tên lớp của PHP là một chút khó khăn. Nếu bạn sẽ sử dụng các lớp WP cốt lõi ( WP_Widgettrong ví dụ bên dưới), bạn phải cung cấp các usecâu lệnh.

use \WP_Widget;

class MyWidget extends WP_Widget
{
   // ...
}

Hoặc bạn có thể sử dụng tên lớp đủ điều kiện - về cơ bản chỉ cần thêm tiền tố vào dấu gạch chéo ngược.

<?php
namespace WPSE\SomeNameSpace;

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

Xác định

Đây là PHP tổng quát hơn, nhưng nó cắn tôi, vì vậy nó ở đây.

Bạn có thể muốn xác định những thứ bạn sẽ sử dụng thường xuyên, như đường dẫn đến plugin của bạn. Sử dụng câu lệnh xác định sẽ đặt mọi thứ trong không gian tên gốc trừ khi bạn rõ ràng chuyển không gian tên vào đối số đầu tiên của định nghĩa.

<?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__));

Bạn cũng có thể sử dụng consttừ khóa ở cấp độ gốc của tệp với PHP 5.3 plus. constss luôn ở trong không gian tên hiện tại, nhưng kém linh hoạt hơn một definecuộc gọi.

<?php
namespace WPSE\SomeNameSpace;

// in the current namespace
const MY_CONST = 1;

// this won't work!
const MY_PATH = plugin_dir_path(__FILE__);

Xin vui lòng thêm bất kỳ lời khuyên nào khác mà bạn có thể có!


16

Đây là một câu trả lời năm 2017.

Tự động tải là tuyệt vời. Không gian tên là tuyệt vời.

Mặc dù bạn có thể tự cuộn nó, nhưng vào năm 2017, sẽ hợp lý nhất khi sử dụng Trình soạn nhạc tuyệt vời và có mặt khắp nơi để xử lý các yêu cầu PHP của bạn. Trình soạn thảo hỗ trợ cả tự động tải PSR-0PSR-4 , nhưng trước đây đã bị từ chối từ năm 2014, vì vậy hãy sử dụng PSR-4. Nó làm giảm sự phức tạp của các thư mục của bạn.

Chúng tôi giữ mỗi plugin / chủ đề của mình trong kho Github của riêng mình, mỗi plugin có composer.jsontệp và composer.locktệp riêng.

Đây là cấu trúc thư mục chúng tôi sử dụng cho các plugin của chúng tôi. (Chúng tôi không thực sự có một plugin được gọi awesome-plugin, nhưng chúng ta nên.)

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/*

Nếu bạn cung cấp một composer.jsontệp thích hợp , Trình soạn thảo sẽ xử lý khoảng cách tên và tự động tải tại đây.

{
    "name": "awesome-company/awesome-plugin",
    "description": "Wordpress plugin for AwesomeCompany website, providing awesome functionality.",
    "type": "wordpress-plugin",
    "autoload": {
        "psr-4": {
            "AwesomeCompany\\Plugins\\AwesomePlugin\\": "src"
        }
    }
}

Khi bạn chạy composer install, nó sẽ tạo vendorthư mục và vendor/autoload.phptệp sẽ tự động tải tất cả các tệp có khoảng cách tên của bạn src/và bất kỳ thư viện nào khác mà bạn có thể yêu cầu.

Sau đó, ở đầu tệp plugin chính của bạn (mà đối với chúng tôi là awesome-plugin.php), sau siêu dữ liệu plugin của bạn, bạn chỉ cần:

// Composer autoloading.
require_once __DIR__ . '/vendor/autoload.php';

...

Tính năng thưởng

Không cần thiết, nhưng chúng tôi sử dụng bản tóm tắt Bedrock Wordpress để sử dụng Trình soạn thảo ngay từ đầu. Sau đó, chúng tôi có thể sử dụng Trình soạn thảo để lắp ráp các plugin mà chúng tôi cần thông qua Trình soạn thảo, bao gồm cả plugin của riêng bạn mà bạn đã viết ở trên. Ngoài ra, nhờ WPackagist , bạn có thể yêu cầu bất kỳ plugin nào khác từ Wordpress.org (xem ví dụ về cool-themecool-pluginbên dưới).

{
  "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"
    ]
  }
}

Lưu ý 1: Nhận xét không hợp pháp trong JSON, nhưng tôi đã chú thích tệp ở trên để rõ ràng hơn.

Lưu ý 2: Tôi đã băm nhỏ một số bit của tệp Bedrock soạn sẵn cho ngắn gọn.

Lưu ý 3: Đây là lý do tại sao typetrường trong composer.jsontệp đầu tiên có ý nghĩa. Trình soạn thảo tự động thả nó vào web/app/pluginsthư mục.


Đánh giá cao câu trả lời của bạn, rất hữu ích! Nhưng tôi tò mò về "bootstrap.php" mà bạn đang đề cập đến. Nó chứa cái gì? :)
INT

1
Có một tệp bootstrap.php là một điều phong cách tôi làm trong hầu hết các dự án của mình, trong hoặc ngoài WP. Bootstrapper của tôi thường chỉ kiểm tra các thiết lập và các biến môi trường; Mục đích chính của nó là để đảm bảo plugin của tôi luôn có những gì nó cần để chạy, bất kể nó được chạy từ bên trong WP hay dưới dạng một ứng dụng PHP độc lập.
haz

4

Tôi sử dụng tự động tải (vì plugin của tôi có vô số lớp - một phần vì nó bao gồm Twig), chưa bao giờ có sự cố khiến tôi chú ý (plugin được cài đặt> 20.000 lần).

Nếu bạn tự tin rằng bạn sẽ không bao giờ cần phải sử dụng bản cài đặt php không hỗ trợ không gian tên thì bạn vẫn ổn (~ 70% blog wordpress hiện tại không hỗ trợ không gian tên). Một số điều cần lưu ý:

Tôi dường như nhớ rằng các không gian tên không phân biệt chữ hoa chữ thường trong php thông thường nhưng khi sử dụng fastcgi php trên iis - điều này gây ra một số vấn đề đau đầu nếu bạn kiểm tra trên linux và không phát hiện ra một chữ cái viết thường.

Ngoài ra, ngay cả khi bạn chắc chắn rằng mã bạn đang phát triển sẽ chỉ được sử dụng vào> 5.3.0, bạn sẽ không thể sử dụng lại bất kỳ mã nào với các dự án không có sự xa xỉ đó - đó là lý do chính khiến tôi không không gian tên được sử dụng trên các dự án nội bộ. Tôi đã phát hiện ra rằng không gian tên thực sự không thêm rằng nhiều khi so sánh với trường hợp đau đầu có thể xảy ra cần phải loại bỏ phụ thuộc vào chúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.