Plugin authors: best practice on how to initialize or instantiate your classes properly

Today, I ran into code like this.

<?php

class Badly_Designed_Plugin {

  public function __construct() {
    add_action( 'woocommerce_after_my_account', array( $this, 'display_something_useless' ) );
  }

  public function display_something_useless() {
    echo "I am a very badly designed plugin!";
    echo "I will make people sad.";
  }

}
new Badly_Designed_Plugin();

So what’s the problem here?

There is no way to remove display_something_useless() function from ‘woocommerce_after_my_account‘ action.*

Normally, I would do this:

remove_action(
  'woocommerce_after_my_account', 
  [$instance_of_badly_designed_plugin, 'display_something_useless']
);

However, there is no way for me to access the instance of Badly_Designed_Plugin class. By doing:

new Badly_Designed_Plugin();

..it’s created and just left to hang around in the void with no a reference to it. Don’t do this.

Instead, if your class is supposed to have a single instance of it ever, just use a Singleton.

Example:

<?php

class Nicely_Designed_Plugin {

  private static $instance;

  public static function get_instance() {
    if (null === static::$instance) {
      static::$instance = new static();
    }
        
    return static::$instance;
  }

  protected function __construct() {
    add_action( 'woocommerce_after_my_account', array( $this, 'display_something_useless' ) );
  }

  public function display_something_useless() {
    echo "I am a very nicely designed plugin.";
    echo "If someone wants to customize me, they can do it!";
  }

}
Nicely_Designed_Plugin::get_instance();

Now, calling Nicely_Designed_Plugin::get_instance() will always return the same instance of Nicely_Designed_Plugin – the instance that’s tied to that WooCommerce action.

So in order to get rid of that useless action, I can do this:

$instance_of_badly_designed_plugin = Nicely_Designed_Plugin::get_instance();
remove_action(
  'woocommerce_after_my_account', 
  [$instance_of_badly_designed_plugin, 'display_something_useless']
);

 

And no, singletons are not inherently evil. They are evil if used in the wrong context. A small WordPress plugin is a perfectly okay place to use a Singleton.


* Actually, there is a way, though it’s pretty bad if you have to use it. See here and here.

Indrek Kõnnussaar

I'm a veteran Wordpress developer, context-driven tester, security enthusiast and the mastermind behind Codelight. I love building stuff that works and fixing stuff that doesn't.

Write me directly indrek@codelight.eu
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×