การโหลดอัตโนมัติและ Namespaces ในปลั๊กอิน WordPress และธีม: มันใช้งานได้ไหม


70

มีใครใช้การโหลดอัตโนมัติและ / หรือ PHP namespaces ภายในปลั๊กอินหรือชุดรูปแบบ?

ความคิดในการใช้พวกเขา? อันตรายใด ๆ ผิดพลาด?

หมายเหตุ: เนมสเปซเป็น PHP 5.3 ขึ้นไปเท่านั้น สมมติว่าคุณรู้ว่าคุณกำลังเผชิญกับเซิร์ฟเวอร์ที่คุณรู้ว่ามี PHP 5.3 หรือสูงกว่า

คำตอบ:


89

โอเคฉันมีสองโครงการใหญ่ที่ฉันควบคุมเซิร์ฟเวอร์ได้เพียงพอที่จะกำหนดชื่อและพึ่งพาการโหลดอัตโนมัติ

ขึ้นก่อน การโหลดอัตโนมัติยอดเยี่ยม ไม่ต้องกังวลเกี่ยวกับความต้องการเป็นสิ่งที่ค่อนข้างดี

นี่คือตัวโหลดที่ฉันใช้ในโปรเจ็กต์สองสามตัว ตรวจสอบเพื่อให้แน่ใจว่าคลาสอยู่ในเนมสเปซปัจจุบันก่อนแล้วค่อยไปถ้าไม่ใช่ จากนั้นเป็นเพียงการจัดการสตริงเพื่อหาชั้นเรียน

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

หนึ่งสามารถปรับได้อย่างง่ายดายสำหรับการใช้งานโดยไม่ต้อง namespaces สมมติว่าคุณนำหน้าปลั๊กอิน / ชุดรูปแบบของคุณอย่างสม่ำเสมอคุณสามารถทดสอบคำนำหน้านั้นได้ จากนั้นใช้เครื่องหมายขีดล่างในชื่อคลาสเป็นตัวยึดตำแหน่งสำหรับตัวคั่นไดเรกทอรี หากคุณใช้คลาสจำนวนมากเป็นไปได้ว่าคุณอาจต้องการใช้ตัวโหลดอัตโนมัติคลาสแมปบางประเภท

Namespaces และ Hooks

ระบบ hooks ของ WordPress ใช้งานได้โดยใช้call_user_func(และcall_user_func_array) ซึ่งใช้ชื่อฟังก์ชั่นเป็นสตริงและเรียกพวกมันเมื่อมีการเรียกใช้ฟังก์ชันdo_action(และต่อมาcall_user_func)

ด้วยเนมสเปซนั่นหมายความว่าคุณจะต้องผ่านชื่อฟังก์ชันที่ผ่านการรับรองโดยสมบูรณ์ซึ่งรวมถึงเนมสเปซไว้ใน hooks

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

หากคุณใส่ตะขอลงในคลาสเสมอมันง่ายกว่า อินสแตนซ์สร้างมาตรฐานของคลาสและ hooks ทั้งหมดในตัวสร้างด้วยการ$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!
    }
}

ใช้คลาสหลัก

ความละเอียดของ classname ของ 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 บวก constss มักจะอยู่ใน namespace ปัจจุบัน แต่มีความยืดหยุ่นน้อยกว่าการdefineโทร

<?php
namespace WPSE\SomeNameSpace;

// in the current namespace
const MY_CONST = 1;

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

โปรดเพิ่มเคล็ดลับอื่น ๆ ที่คุณอาจมี!


16

นี่คือคำตอบปี 2017

การโหลดอัตโนมัติยอดเยี่ยม การกำหนดชื่อน่ากลัว

แม้ว่าคุณจะสามารถม้วนมันด้วยตัวคุณเองได้ในปี 2560 แต่มันก็สมเหตุสมผลดีที่จะใช้Composer ที่งดงามและแพร่หลายเพื่อจัดการกับความต้องการ PHP ของคุณ นักแต่งเพลงสนับสนุนการโหลดอัตโนมัติทั้ง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ไฟล์ที่เหมาะสมนักแต่งเพลงจะจัดการการเว้นวรรคชื่อและการโหลดอัตโนมัติที่นี่

{
    "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: ฉันได้ตัดบางส่วนของไฟล์ Bedrock สำเร็จรูปเพื่อความสั้น

หมายเหตุ 3: นี่คือสาเหตุที่typeฟิลด์ในcomposer.jsonไฟล์แรกมีความสำคัญ นักแต่งเพลงจะวางลงในweb/app/pluginsไดเรกทอรีโดยอัตโนมัติ


ขอบคุณคำตอบของคุณมีประโยชน์มาก! แต่ฉันอยากรู้เกี่ยวกับ "bootstrap.php" ที่คุณอ้างถึง มันมีอะไรบ้าง :)
INT

1
การมีไฟล์ bootstrap.php เป็นสิ่งที่มีสไตล์ที่ฉันทำในโครงการส่วนใหญ่ของฉันไม่ว่าจะในหรือนอก WP bootstrapper ของฉันปกติตรวจสอบการตั้งค่าและตัวแปรสภาพแวดล้อม วัตถุประสงค์หลักคือเพื่อให้แน่ใจว่าปลั๊กอินของฉันมีสิ่งที่ต้องใช้เสมอโดยไม่คำนึงว่าจะถูกเรียกใช้จากภายใน WP หรือเป็นแอป PHP แบบสแตนด์อโลน
Haz

4

ฉันใช้การโหลดอัตโนมัติ (เนื่องจากปลั๊กอินของฉันมีการโหลดคลาส - ส่วนหนึ่งเป็นเพราะมี Twig) ไม่เคยมีปัญหามาถึงความสนใจของฉัน (ติดตั้งปลั๊กอิน> 20,000 ครั้ง)

หากคุณมั่นใจว่าคุณจะไม่จำเป็นต้องใช้การติดตั้ง php ที่ไม่รองรับเนมสเปซอีกต่อไปคุณก็สบายดี (ประมาณ 70% ของบล็อก WordPress ปัจจุบันไม่รองรับเนมสเปซ) สิ่งที่ควรทราบ:

ฉันดูเหมือนจะจำได้ว่า namespaces ไม่ตรงตามตัวพิมพ์ใหญ่ - เล็กใน php ปกติ แต่เมื่อใช้ fastcgi php บน iis - นี่ทำให้ปวดหัวบางอย่างถ้าคุณทดสอบบน linux และไม่เห็นอักษรตัวพิมพ์เล็กอันธพาล

แม้ว่าคุณจะแน่ใจว่ารหัสที่คุณกำลังพัฒนานั้นจะใช้กับ> 5.3.0 คุณจะไม่สามารถใช้รหัสซ้ำกับโครงการที่ไม่มีความหรูหรานั้น - นั่นคือเหตุผลหลักว่าทำไมฉันถึงไม่ได้ ใช้เนมสเปซในโครงการภายใน ฉันได้พบว่า namespaces จริงๆไม่ได้เพิ่มที่มากเมื่อเทียบกับอาการปวดหัวเป็นไปได้ของการมีการลบพึ่งพาพวกเขา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.