5

I am trying to walk away from the Singleton pattern when it comes to develop plugins for WordPress.

Why?

Because I have been reading in some sources (here, here, here, here ...) and came up with the conclusion that they are a bad thing. Or at least, not something one should use just because.

Why would I need a Singleton-like behavior?

Because I want to have an object with properties where multiple classes along different plugins can write and read those properties.

And I sincerely do not know how to approach this.

Can you please let me know how you would do it?

There may be different cases with different solutions, so I will suppose a real example.

Example:

A plugin called "Example Form" creates a custom form on the WordPress site.

The form is processed via a method added to the init hook by the plugin class.

public static function setup_actions_and_filters(){
   $this_class = new self();
   add_action('init', [$this_class, 'process_form']);
....

And while processing the form I may want to add some error or success messages to the active instance, so I can then display those messages in a theme doing somethig like:

$instance_of_PLUGINCLASS->show_errors();

But I don't have access to the "original" instance because I called a satic setup method in the main plugin file.

PLUGINCLASS::setup_actions_and_filters();

And that is why a common solution is to make the PLUGINCLASS use the Singleton pattern, which I want to avoid.

Did I come up with my own ideas?

Yes.

I thought about:

  • Using the database - Horrible idea
  • Using cookies - Terrible idea
  • Using sessions - Not so nice
  • Going from one request to the other sending GET or POST info - Vulnerable and dirty
  • Using globals - I have read many times that it's not a good idea to use them
  • Using WP Object Cache (see Singleton VS Object Caching)
  • Why do you think singletons are bad? What are the specific problems you're trying to solve, or development issues that you think you might have in the future? – mozboz Jul 19 at 11:16
  • 2
    I stand by the answer I wrote here: wordpress.stackexchange.com/a/369101/176814 . Wordpress is a huge compicated bit of software, and there's very little point considering good design when the question is not designing good software on a clean sheet of paper with full choice of all technologies, the quesiton is designing software to get stuff done inside the constraints of Wordpress and PHP. – mozboz Jul 20 at 9:51
  • 1
    @mozboz Thanks for the insight, seems it's a fair way to go. – Alvaro Franz Jul 20 at 14:52
  • 1
    Well this is from the source code of those calls: function wp_cache_init() { $GLOBALS['wp_object_cache'] = new WP_Object_Cache(); } ;-) So.. there's no such thing as a free lunch. If you can't pass back and forth the variables you need through whoever called you then you have to use either globals or static variables on classes. – mozboz Jul 20 at 18:17
  • 1
    But, if you have some design goals which are about making a lot of code that needs to share variables more easy to work on and debug, then I think it could be a good idea to add WP_Cache style access control onto that global state. It gives you a point where, if you really wanted to, you could see when each value was being set/get, and even by who, if you asked the caller to give you an identifier. Obviously temper this with what all the good advice says about why it's bad to use singletons - this might be useful advice to any code that has global state. – mozboz Jul 20 at 18:26
3

Thought it might be useful to summarise some of the points from the comments here. (Note: 'Singleton' is a name given to the pattern of storing an instance of a class in a static property of a class, usually the same one, so here 'singleton' and 'static property' are used more or less interchangeably)

Singleton Dogma

Heed the good advice about singletons and the warnings about bad habits they can get you in, but don't let that stop you using singletons or static properties. Like using global variables, or not structuring your code well into functions and files, or not commenting your code or naming your variables well; or a thousand other bad programming habits, if you're not aware of the strucutres you're using and taking care of good programming habits your life (and maybe other peoples' lives) will get harder later.

There are only 2 options

Without going outside of the PHP process and its memory, you simply only have two options to share variables between scopes:

  • Global variables
  • Static properties on classes.

There are no other options. Within the Wordpress codebase, where you can't change the structure of swathes of code just to pass your variable around neatly, you therefore have to use one of these two options. The question is not if but how you use them.

Using appropriate complexity

Here are my thoughts on the basic options available. It's worth considering which of these makes sense for you. Good development without premature optimisation would suggest that you should use the simplest one that supports what you know about your requirements now, with flexibility to change your code if/when you need to.

Get Creative, Use Wordpress Ways

Get creative. Access control on top of a configuration class? Use an array or a queue data structure instead of a single variable? Employ Wordpress's filters to pass values around and expose import interfaces in your code to other users?

Some little neat features might save you a ton of heartache to catch situations where, for example:

  • You need to set a value exactly once and read it exactly once
  • You want to allow any number of values to be set from many different places and then read them all in one place
  • You want to debug by seeing who set/get a variable in what order
  • You want to add caching between PHP page loads / sessions
  • You want to make the internals pf your plugin accessible to other people who may want to extend its functionality / content
| improve this answer | |
  • Thanks for your help, it has really clarified my ideas on the topic. – Alvaro Franz Jul 21 at 7:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.