add_action tham chiếu một lớp


38

Có thể tham chiếu một lớp thay vì một hàm trong 'add_action' không? Dường như không thể tìm ra nó. Đây chỉ là một ví dụ cơ bản của chức năng trong câu hỏi.

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

Vì vậy, yeah, điều đó không làm việc. Tôi cũng đã thử:

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

Và:

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

Và cũng:

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

Có cách nào tôi có thể làm điều này mà không phải tạo một hàm riêng biệt tải lớp không? Tôi muốn có thể chạy trình xây dựng lớp thông qua add_action. Đó là tất cả những gì cần phải được tải để có được quả bóng lăn.

Câu trả lời:


69

Không, bạn không thể 'khởi tạo' hoặc khởi tạo lớp thông qua một cái móc, không trực tiếp. Một số mã bổ sung luôn được yêu cầu (và đó không phải là điều mong muốn để có thể làm điều đó, vì bạn đang mở một hộp giun cho chính mình.

Đây là một cách tốt hơn để làm điều đó:

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

Tất nhiên người ta có thể tạo một lớp giao diện để đơn giản hóa nó cho trường hợp chung hơn nữa:

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

Lưu ý rằng với tư cách là một giao diện, bạn không thể trực tiếp tạo một đối tượng thuộc loại này, nhưng bạn có thể tạo một lớp con, cho phép bạn nói:

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

Sau đó sẽ tự động thêm tất cả các hook, bạn chỉ cần xác định chính xác những gì đang được thực hiện trong một lớp con và sau đó tạo nó!

Về xây dựng

Tôi sẽ không thêm một hàm tạo như một hàm hook, đó là một cách thực hành tồi và có thể dẫn đến nhiều sự kiện bất thường. Ngoài ra, trong hầu hết các ngôn ngữ, hàm tạo trả về đối tượng đang được khởi tạo, vì vậy nếu hook của bạn cần trả về một cái gì đó như trong bộ lọc, nó sẽ không trả về biến được lọc như bạn muốn, mà thay vào đó, nó sẽ trả về đối tượng lớp.

Gọi một hàm tạo hoặc hàm hủy là một thực hành lập trình rất, rất, rất tệ, bất kể bạn đang sử dụng ngôn ngữ nào và không bao giờ nên thực hiện.

Các nhà xây dựng cũng nên xây dựng các đối tượng, để khởi tạo chúng sẵn sàng để sử dụng, không phải cho công việc thực tế. Công việc được thực hiện bởi đối tượng nên ở một chức năng riêng biệt.

Các phương thức lớp tĩnh và hoàn toàn không cần khởi tạo / khởi tạo

Nếu phương thức lớp của bạn là một phương thức lớp tĩnh, bạn có thể chuyển tên của lớp trong dấu ngoặc kép thay vì $thisnhư dưới đây:

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

Đóng cửa & PHP 5.3

Đáng buồn thay, bạn không thể tránh dòng tạo lớp mới. Giải pháp duy nhất khác để bỏ qua nó sẽ liên quan đến mã tấm nồi hơi vẫn có dòng đó và sẽ yêu cầu PHP 5.3+, ví dụ:

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

Tại điểm nào bạn cũng có thể bỏ qua lớp và chỉ sử dụng một hàm:

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

Nhưng hãy nhớ rằng bây giờ bạn đã giới thiệu bóng ma của các chức năng ẩn danh. Không có cách nào để loại bỏ hành động trên bằng cách sử dụng remove_actionvà điều này có thể và gây ra nỗi đau lớn cho các nhà phát triển phải làm việc với mã người khác.

Trên Ampersands

Bạn có thể thấy các hành động được sử dụng như thế này:

array( &$this, 'getStuffDone' );

Điều này là xấu . &đã được thêm lại trong PHP 4 khi các đối tượng được truyền dưới dạng giá trị, không phải là tham chiếu. PHP 4 đã hơn một thập kỷ và không được WordPress hỗ trợ trong một thời gian rất dài.

Không có lý do để sử dụng &thiskhi thêm hook và bộ lọc và việc xóa tham chiếu sẽ không gây ra vấn đề gì và thậm chí có thể cải thiện khả năng tương thích với các phiên bản PHP trong tương lai

Sử dụng cái này thay thế:

array( $this, 'getStuffDone' );

Được. Cảm ơn bạn từ tất cả những điều đó; thực sự học được khá nhiều. Bây giờ tôi thực sự chỉ cảm thấy thoải mái trong lớp học dựa trên PHP. Đây là những gì tôi đã làm, và nó hoạt động, nhưng bạn có thể cho tôi biết nếu đó là thực hành xấu / không đúng cách? Tôi đã khởi tạo lớp bên trong một hàm tĩnh, trong chính lớp đó. Sau đó tham chiếu hàm tĩnh trong add_action. Xem liên kết này: pastebin.com/0idyPwwY
Matthew Ruddy

vâng, bạn có thể làm theo cách đó, mặc dù tôi có thể tránh sử dụng $classlàm tên biến của bạn, những từ đó có xu hướng được bảo lưu. Tôi nghĩ rằng bạn đang tránh đường để tránh nói điều gì đó tương tự $x = new Y();trong phạm vi toàn cầu và bạn đang thêm sự phức tạp khi không cần thiết. Nỗ lực của bạn để giảm số lượng mã được viết có liên quan đến việc viết thêm mã!
Tom J Nowell

Tôi đã chỉ ra trong tất cả các trường hợp trên, bạn sẽ tốt hơn khi sử dụng một hàm chứ không phải là một lớp, vì lớp đó sẽ bị loại bỏ và phục vụ cho cùng một mục đích. Đó là một sự lãng phí tài nguyên. Hãy nhớ rằng, có một chi phí để tạo và phá hủy một đối tượng, bạn muốn có một vài đối tượng và bạn muốn chúng tồn tại lâu dài
Tom J Nowell

Điểm tốt. Thay đổi cách tôi đã nhìn vào nó. Tôi nghĩ rằng tôi sẽ gọi nó trong phạm vi toàn cầu thay vào đó, tránh mã thêm.
Matthew Ruddy

1
Tôi muốn thêm rằng nếu bạn tình cờ đặt lớp của mình vào một không gian tên, bạn cũng sẽ phải thêm nó hoặc add_action () / add_filter () sẽ không tìm thấy nó - như thế này:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab

10

Lớp ví dụ

Ghi chú:

  • Ban đầu lớp chỉ một lần
    • Gọi mức độ ưu tiên 0, vì vậy bạn có thể sử dụng cùng một hook với mức ưu tiên mặc định sau
    • Gói lại trong một ! class_existsđể tránh gọi nó hai lần và đặt người gọi init vào trong
  • Tạo inithàm và lớp varstatic
  • Gọi hàm tạo từ bên trong init của bạn, khi bạn gọi lớp new self.

Đây là một ví dụ

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+

Xin vui lòng , để lại &. Chúng tôi đã vượt quá 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();
}

Vui lòng chỉnh sửa câu trả lời của bạn và thêm một lời giải thích: tại sao điều đó có thể giải quyết vấn đề?
fuxia

0

Bạn có thể kích hoạt các sự kiện trong lớp mà không cần phải tải nó ban đầu . Điều này rất hữu ích nếu bạn không muốn tải toàn bộ lớp trước, nhưng cần truy cập vào các bộ lọc và hành động của WordPress.

Đây là một ví dụ rất đơn giản

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

Đây là một phiên bản rất đơn giản của câu trả lời của Kaiser nhưng thể hiện dưới dạng đơn giản hành vi. Có thể có ích cho những người lần đầu tiên nhìn vào phong cách này.

Các phương thức khác vẫn có thể khởi tạo đối tượng nếu được yêu cầu. Cá nhân tôi đang sử dụng phương pháp này để cho phép các phần tùy chọn trong plugin của mình xử lý các tập lệnh, nhưng chỉ kích hoạt đối tượng theo yêu cầu AJAX.


0

Điều này làm việc cho tôi:

class foo
{
    public static function bar()
    {
        echo 'it works!';
    }
}

add_action('foo_bar', array('foo', 'bar'));

0

Nói chung, bạn sẽ không thêm toàn bộ lớp vào một cái móc. Các add_action()/ add_filter()hook mong đợi các hàm gọi lại , có thể được tham chiếu từ trong một lớp .

Giả sử bạn có một init()chức năng bên trong lớp của mình, rằng bạn muốn nối vào inithook WordPress .

Đặt add_action()cuộc gọi của bạn trong lớp và sau đó xác định cuộc gọi lại như vậy:

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

(Lưu ý: Tôi cho rằng lớp của bạn được đặt đúng tên, nếu không, hãy chắc chắn để không gian tên các hàm gọi lại của bạn.)


Còn nếu lớp hiện tại chưa được bắt đầu thì sao? Tôi đã cố gắng sử dụng add_action để thực sự bắt đầu, vì vậy tôi không phải thêm $ var = new MyClass (); trước đó ở nơi khác.
Matthew Ruddy

Bạn có thể không chỉ viết một cuộc gọi lại để khởi tạo lớp học của bạn tại init(hoặc bất cứ nơi nào bạn cần nó)?
Chip Bennett

0

Bạn sẽ có thể làm điều đó bằng cách chuyển tên lớp thay vì đối tượng được khởi tạo:

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

(Về lý thuyết, giải pháp khác của bạn cũng nên hoạt động

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

Không chắc chắn tại sao nó không. Có lẽ nếu bạn không gọi bằng cách tham khảo?)


Đầu tiên không hoạt động. Chỉ cần làm cho trang trống. Công việc thứ hai, nhưng chỉ vì lớp đã được bắt đầu trong dòng đầu tiên. Nó loại thất bại mục đích thêm hành động, bởi vì lớp đã được bắt đầu. Nhưng nó không làm những gì tôi đang cố gắng làm, đó là khởi đầu lớp thông qua hành động. Trong mã thực tế tôi đang làm việc, hành động không phải là 'admin_init' mà là hành động tùy chỉnh trong một lớp khác. Tôi không muốn chức năng 'MyClass' được bắt đầu nếu hành động trong lớp khác không có ở đó. Xin lỗi nếu tôi thiếu một cái gì đó; học khi tôi đi
Matthew Ruddy

Vâng, tôi đã sai. Điều đó chỉ hoạt động nếu bạn đang gọi một initphương thức tĩnh . Xem wordpress.stackexchange.com/a/48093/14052
Hẻm núi Boone
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.