add_action อ้างอิงคลาส


38

เป็นไปได้ที่จะอ้างอิงคลาสแทนฟังก์ชั่นใน 'add_action' หรือไม่? ดูเหมือนจะไม่สามารถคิดออก นี่เป็นเพียงตัวอย่างพื้นฐานของฟังก์ชันที่เป็นปัญหา

add_action( 'admin_init', 'MyClass' );
class MyClass {
     function __construct() {
          .. This is where stuff gets done ..
     }
}

ใช่นั่นมันใช้งานไม่ได้ ฉันยังลอง:

$var = new MyClass();
add_action( 'admin_init', array( &$var ) );

และ:

$var = new MyClass();
add_action( 'admin_init', array( &$var, '__construct' ) );

และนอกจากนี้ยังมี:

add_action( 'admin_init', 'MyClass::__construct' );

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

คำตอบ:


69

ไม่คุณไม่สามารถ 'กำหนดค่าเริ่มต้น' หรือสร้างอินสแตนซ์ของคลาสผ่านทาง hook ไม่ใช่โดยตรง ต้องมีรหัสเพิ่มเติมอยู่เสมอ (และไม่ใช่สิ่งที่พึงปรารถนาที่จะทำเช่นนั้นเมื่อคุณเปิดเวิร์มกระป๋องสำหรับตัวคุณเอง

นี่เป็นวิธีที่ดีกว่าในการทำ:

class MyClass {
     function __construct() {
          add_action( 'admin_init',array( $this, 'getStuffDone' ) );
     }
     function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
$var = new MyClass();

แน่นอนว่าหนึ่งสามารถสร้างคลาสอินเตอร์เฟสเพื่อทำให้ง่ายขึ้นสำหรับเคสทั่วไปยิ่งขึ้นไปอีก:

class IGetStuffDone {
    function IGetStuffDone(){
        add_action( 'admin_init',array( $this, 'getStuffDone' ) );
    }
    public abstract function getStuffDone();
}

โปรดทราบว่าในฐานะที่เป็นอินเทอร์เฟซคุณไม่สามารถสร้างวัตถุประเภทนี้โดยตรง แต่คุณสามารถสร้างคลาสย่อยโดยให้คุณพูดว่า:

class CDoingThings extends IGetStuffDone {
    function getStuffDone(){
        // doing things
    }
}
$var = new CDoingThings();

ซึ่งจะเพิ่ม hooks ทั้งหมดโดยอัตโนมัติคุณเพียงแค่ต้องกำหนดสิ่งที่ถูกทำในคลาสย่อยและสร้างมันขึ้นมา!

ในการก่อสร้าง

ฉันจะไม่เพิ่มนวกรรมิกของฟังก์ชั่นฮุคมันเป็นการฝึกฝนที่ไม่ดีและสามารถนำไปสู่เหตุการณ์ที่ผิดปกติมากมาย ในภาษาส่วนใหญ่คอนสตรัคเตอร์จะส่งคืนออบเจ็กต์ที่กำลังถูกอินสแตนซ์ดังนั้นหากตะขอของคุณต้องการส่งคืนบางอย่างในตัวกรองมันจะไม่ส่งคืนตัวแปรที่กรองตามที่คุณต้องการ แต่มันจะส่งคืนคลาสอ็อบเจ็กต์

การโทรหาคอนสตรัคเตอร์หรือ destructor นั้นเป็นวิธีการเขียนโปรแกรมที่แย่มาก ๆ ไม่ว่าคุณจะใช้ภาษาใดและไม่ควรทำ

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

วิธีการเรียนแบบคงที่และไม่จำเป็นต้องยกตัวอย่าง / เริ่มต้นเลย

หากวิธีการเรียนของคุณเป็นวิธีการเรียนแบบคงที่คุณสามารถส่งชื่อของชั้นเรียนในคำพูดมากกว่า$thisที่แสดงด้านล่าง:

class MyClass {
     public static function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
add_action( 'admin_init', array('MyClass','getStuffDone' ) );

การปิด & PHP 5.3

น่าเศร้าที่คุณไม่สามารถหลีกเลี่ยงสายที่สร้างคลาสใหม่ได้ ทางออกเดียวที่จะข้ามมันจะเกี่ยวข้องกับรหัสจานหม้อไอน้ำที่ยังคงมีบรรทัดนั้นและจะต้องมี PHP 5.3+ เช่น:

add_action('admin_init',function(){
    $var = new MyClass();
    $var->getStuffDone();
});

ณ จุดนี้คุณอาจข้ามคลาสและใช้ฟังก์ชัน:

add_action('admin_init',function(){
    // do stuff
});

แต่จำไว้ว่าตอนนี้คุณได้เปิดตัวอสุรกายของฟังก์ชั่นนิรนาม ไม่มีวิธีที่จะลบการดำเนินการข้างต้นโดยใช้remove_actionและสิ่งนี้สามารถและทำให้เกิดความเจ็บปวดอย่างมากสำหรับนักพัฒนาที่ต้องทำงานกับรหัสประชาชนอื่น ๆ

บนเครื่องหมาย

คุณอาจเห็นการกระทำที่ใช้ในลักษณะนี้:

array( &$this, 'getStuffDone' );

นี่มันแย่มาก &ถูกเพิ่มกลับมาใน PHP 4 เมื่อวัตถุถูกส่งผ่านเป็นค่าไม่ใช่การอ้างอิง PHP 4 มีอายุมากกว่าทศวรรษและไม่ได้รับการสนับสนุนจาก WordPress ในเวลานาน

นอกจากนี้ไม่มีเหตุผลที่จะใช้&thisเมื่อมีการเพิ่มตะขอและตัวกรองและลบอ้างอิงจะทำให้เกิดปัญหาใด ๆ และอาจปรับปรุงความเข้ากันได้กับรุ่นอนาคตของ PHP

ใช้สิ่งนี้แทน:

array( $this, 'getStuffDone' );

ตกลง. ขอบคุณจากทั้งหมด; เรียนรู้จริงๆไม่น้อย ตอนนี้ฉันรู้สึกสะดวกสบายในการใช้ PHP ในชั้นเรียนเท่านั้น นี่คือสิ่งที่ฉันได้ทำไปแล้วและมันใช้งานได้ แต่คุณสามารถบอกฉันได้ไหมว่ามันเป็นการปฏิบัติที่ไม่ถูกต้องหรือไม่ถูกต้องหรือไม่? ฉันได้เริ่มชั้นเรียนภายในฟังก์ชั่นคงที่ภายในชั้นเรียนของตัวเอง จากนั้นอ้างอิงฟังก์ชันสแตติกใน add_action ดูลิงค์นี้: pastebin.com/0idyPwwY
Matthew Ruddy

ใช่คุณสามารถทำเช่นนั้นแม้ว่าฉันจะหลีกเลี่ยงการใช้$classเป็นชื่อตัวแปรของคุณคำเหล่านั้นมักจะถูกสงวนไว้ ฉันคิดว่าคุณกำลังจะไปให้พ้นทางเพื่อหลีกเลี่ยงการพูดอะไรที่คล้ายกัน$x = new Y();ในขอบเขตทั่วโลกและคุณกำลังเพิ่มความซับซ้อนที่ไม่จำเป็น ความพยายามในการลดจำนวนรหัสที่เขียนนั้นเกี่ยวข้องกับการเขียนรหัสเพิ่มเติม!
Tom J Nowell

ฉันจะชี้ให้เห็นในทุกกรณีข้างต้นคุณจะดีกว่าการใช้ฟังก์ชั่นมากกว่าคลาสเพราะคลาสนั้นจะถูกยกเลิกไปแล้วและทำหน้าที่เดียวกัน มันเป็นการสิ้นเปลืองทรัพยากร จำไว้ว่ามีค่าใช้จ่ายในการสร้างและทำลายวัตถุคุณต้องการวัตถุน้อยและคุณต้องการให้พวกมันมีอายุยืนยาว
Tom J Nowell

จุดดี. เปลี่ยนวิธีที่ฉันมองมัน ฉันคิดว่าฉันจะเรียกมันในขอบเขตทั่วโลกแทนการหลีกเลี่ยงรหัสพิเศษ
Matthew Ruddy

1
ฉันอยากจะเพิ่มว่าถ้าคุณใส่ชั้นเรียนของคุณในเนมสเปซคุณจะต้องเพิ่มที่เกินไปหรือ add_action () / add_filter () จะไม่พบมัน - เช่นนี้:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab

10

ชั้นเรียนตัวอย่าง

หมายเหตุ:

  • เริ่มชั้นเรียนเพียงครั้งเดียว
    • โทรหาลำดับความสำคัญ 0 ดังนั้นคุณสามารถใช้เบ็ดเดียวกันกับลำดับความสำคัญเริ่มต้นในภายหลัง
    • ล้อมรอบใน! class_existsเพื่อหลีกเลี่ยงการโทรสองครั้งและวางผู้เรียก init ไว้ข้างใน
  • ทำให้initฟังก์ชั่นและคลาส varstatic
  • เรียก constructor จากภายใน init new selfของคุณเมื่อคุณโทรชั้นเรียน

นี่คือตัวอย่าง

if ( ! class_exists( 'WPSESampleClass' ) )
{
    // Init the class on priority 0 to avoid adding priority inside the class as default = 10
    add_action( 'init', array ( 'WPSESampleClass', 'init' ), 0 );

class WPSESampleClass
{
    /**
     * The Class Object
     */
    static private $class = null;

    public static function init()
    {
        if ( null === self::$class ) 
            self :: $class = new self;

        return self :: $class;
    }

    public function __construct()
    {
        // do stuff like add action calls:
        add_action( 'init', array( $this, 'cb_fn_name' ) );
    }

    public function cb_fn_name()
    {
        // do stuff 
    }
} // END Class WPSESampleClass

} // endif;

Php 5+

ได้โปรดออก&ไป เราอยู่เหนือกว่า php4 แล้ว :)


2
if (!class_exists("AllInOneWoo")){
    class AllInOneWoo {
        function __construct(){
            add_action('admin_menu', array($this, 'all_in_one_woo') );
        }
        function all_in_one_woo(){
            $page_title = 'All In One Woo';
            $menu_title = 'All In One Woo';
            $capability = 'manage_options';
            $menu_slug  = 'all-in-one-woo-menu';
            $function   = array($this, 'all_in_one_woo_menu');
            $icon_url   = 'dashicons-media-code';
            $position   = 59;

            add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position);
        }
        function all_in_one_woo_menu(){?>
            <div class="wrap">
                <h1><?php _e('All In One Woo', 'all_in_one_woo'); ?></h1>
            </div>
        <?php }
    }// end class
}// end if

if (class_exists("AllInOneWoo")){       
    $all_in_one_woo = new AllInOneWoo();
}

โปรดแก้ไขคำตอบของคุณและเพิ่มคำอธิบาย: เหตุใดจึงแก้ไขปัญหาได้
fuxia

0

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

นี่เป็นตัวอย่างง่ายๆ

<?php
class MyClass
{
    public static function init()
    {
        add_filter( 'the_content', array('MyClass', 'myMethod') );
    }

    public static function myMethod($content)
    {
        $content = $content . 'Working without loading the object';
    }
}

MyClass::init();

นี่เป็นคำตอบที่ง่ายมากของ Kaiser แต่แสดงให้เห็นถึงพฤติกรรมที่เรียบง่าย อาจเป็นประโยชน์สำหรับผู้ที่ดูสไตล์นี้เป็นครั้งแรก

วิธีการอื่นยังสามารถเริ่มต้นวัตถุได้ถ้าต้องการ ฉันใช้วิธีนี้เป็นการส่วนตัวเพื่อให้ส่วนเสริมของปลั๊กอินของฉันในการจัดคิวสคริปต์ แต่เรียกเฉพาะวัตถุในคำขอ AJAX



0

โดยทั่วไปแล้วคุณจะไม่เพิ่มคลาสทั้งหมดลงในตะขอ add_action()/ add_filter()ตะขอคาดหวังว่าการเรียกกลับฟังก์ชั่นที่สามารถอ้างอิงได้จากภายในชั้นเรียน

สมมติว่าคุณมีinit()ฟังก์ชั่นในชั้นเรียนของคุณที่คุณต้องการเชื่อมต่อลงในinitเบ็ดWordPress

ใส่add_action()สายของคุณไว้ในชั้นเรียนแล้วระบุการโทรกลับดังนี้

add_action( 'init', array( $this, 'init' ) );

(หมายเหตุ: ฉันสมมติว่าคลาสของคุณมีเนมสเปซอย่างถูกต้องมิฉะนั้นต้องแน่ใจว่ากำหนดฟังก์ชันการเรียกกลับของคุณ)


จะเกิดอะไรขึ้นถ้าคลาสปัจจุบันยังไม่ได้เริ่ม? ฉันพยายามใช้ add_action เพื่อเริ่มต้นจริงดังนั้นฉันไม่จำเป็นต้องเพิ่ม $ var = new MyClass (); ก่อนอื่น
Matthew Ruddy

คุณไม่เพียงแค่เขียนโทรกลับเพื่อยกระดับชั้นเรียนของคุณที่init(หรือทุกที่ที่คุณต้องการ)
Chip Bennett

0

คุณควรจะทำได้โดยส่งชื่อคลาสแทนวัตถุที่สร้างอินสแตนซ์:

add_action( 'init', array( 'MyClass', '__construct' ) );

(ในทางทฤษฎีแล้วโซลูชันอื่นของคุณควรทำงานด้วยเช่นกัน

$var = new MyClass();
add_action( 'admin_init', array( $var, '__construct' ) );

ไม่แน่ใจออกหัวทำไมมันไม่ บางทีถ้าคุณไม่โทรหาโดยอ้างอิง?)


อันแรกไม่ทำงาน เพียงแค่ทำให้หน้าเว็บว่างเปล่า การทำงานที่สอง แต่เนื่องจากคลาสได้รับการเริ่มต้นในบรรทัดแรก มันเป็นการเอาชนะจุดประสงค์ของการเพิ่มแอ็คชั่นเพราะคลาสได้เริ่มขึ้นแล้ว แต่มันไม่ได้ทำในสิ่งที่ฉันพยายามทำซึ่งเป็นการเริ่มชั้นเรียนผ่านการกระทำ ในรหัสจริงที่ฉันใช้งานอยู่การกระทำนั้นไม่ใช่ 'admin_init' แต่เป็นการกระทำที่กำหนดเองภายในคลาสอื่น ฉันไม่ต้องการให้มีการเริ่มต้นฟังก์ชัน 'MyClass' หากไม่มีการดำเนินการในคลาสอื่น ขออภัยถ้าฉันทำอะไรบางอย่างหายไป; การเรียนรู้ที่ฉันไป
Matthew Ruddy

ใช่ฉันคิดผิด ใช้งานได้เฉพาะในกรณีที่คุณเรียกใช้initวิธีการคงที่ ดูwordpress.stackexchange.com/a/48093/14052
Boone Gorges
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.