2

I'm currently working on a plugin, which uses the builtin cron functionality of wordpress.

Instead of using PHP4, I want to use PHP5 with inheritance and the singleton design pattern. I run in some limitations with the action & filter hook mechanism and wanted to ask, if you have an other approach for this problem.

I've stripped out all not relevant parts from the example code. If you need the full code for demostration, please post here so I can add an pastbin link.

Example:

In the base class "Cron" I want to declare all methods, which describes a cron job. To register a new cron-entry I use add_action with the hookname and a callable method.

The problem:

To call this action-hook, the builtin wordpress function do_action needs access from outside to this method. To solve the problem, I declared the method as public static.

But this doesn't seems right either. The method should not be accessable from outside. It should be private. Only the MyCron class should have the permission to access this method. I tried different things as you can see in the comment block in the example.

Only if I declare the constructor public (which would destroy the singleton pattern), I'm able to set the method to private. But then, everytime I add an event, a new MyCron object would be created.

Any suggestions?

Thanks, Roman


class Cron {
    private $_events;

    protected function __construct() {
        $this->_events = array();
    }

    protected function addEvent($timestamp, $recurrence, $hookname, $hookmethod, $args = array()) {
        $this->_events[] = $hookname;

        if (!wp_next_scheduled($hookname)) {
            wp_schedule_event($timestamp, $recurrence, $hookname, $args);
        }

        add_action($hookname, $hookmethod);
    }
}

class MyCron extends Cron {
    private static $_instance = null;

    public static function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    protected function __construct() {
        parent::__construct();

        /* Note: 
         * The passing action hook must be public static to be callable from outside. An other option is to declare the constructor
         * public. But this means, everytime I add e new event I will create an new object of MyCron. This is the reason why I
         * the singleton php design pattern with a private/protected constructor.
         * 
         * This doesn't work either:
         * 1) $this->addEvent(time(), 'daily', 'webeo-daily-event', 'MyCron::getInstance->myDailyEvent');
         * 2) $this->addEvent(time(), 'daily', 'webeo-daily-event', 'MyCron::getInstance::myDailyEvent');
         * 3) $this->addEvent(time(), 'daily', 'webeo-daily-event', array('MyCron::getInstance', 'myDailyEvent'));
         * 4) $this->addEvent(time(), 'daily', 'webeo-daily-event', create_function('', 'return MyCron::getInstance()->myDailyEvent();'));
         * 5) $this->addEvent(time(), 'daily', 'webeo-daily-event', function() { return MyCron::getInstance()->myDailyEvent(); });
         */
        $this->addEvent(time(), 'daily', 'webeo-daily-event', array($this, 'myDailyEvent'));

    }

    public static function myDailyEvent() {
        // do this every day with wp cron
    }
}
2
  • 2
    I guess, you have just found out why the Singleton is an anti-pattern.
    – fuxia
    Mar 17, 2011 at 18:57
  • 1
    Thank you for the hint. I've already read about the anti-pattern thematic, but never understood what the problem was. For people in the same situation, please read this. A possible alternative with factory method and dependency injection is described here.
    – Roman
    Mar 18, 2011 at 9:35

1 Answer 1

4

You don’t have to declare the constructor public, just the action hook function.

Example:

<?php
/*
Plugin Name: Singleton Action
*/

class Singleton_Demo
{
    /**
     * @static $instance Objekt
     * @access private;
     */
    private static $_instance   = NULL;

    protected function __construct() {}
    private final function __clone() {}

    public static function getInstance()
    {
        if ( self::$_instance === NULL )
        {
            self::$_instance = new self;
        }

        return self::$_instance;
    }

    public function hook_test()
    {
        print '<p>Works!</p>';
    }
}

add_action( 'wp_footer', array ( Singleton_Demo::getInstance(), 'hook_test' ) );

Anyway, I wouldn’t use a Singleton. :)

2
  • Well thanks, I've already tried this as you can see in my first post. Anyway, i've already removed the singleton from my class and saved the object in a objectstore a.k.a registry-pattern. I don't know if this is the way to go. Because know, every one could instantiate an other object of Cron. In my oppinion, the singleton pattern isn't that bad if u don't use it as a global access point.
    – Roman
    Mar 22, 2011 at 8:10
  • I've just re-read your answer and found my fault here. I've used array('MyCron::getInstance', 'myDailyEvent')); instead of array(MyCron::getInstance(), 'myDailyEvent'));. Well, I don't need it anymore but thank you anyway ;).
    – Roman
    Mar 31, 2011 at 19:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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