Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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
    }
}
share|improve this question
2  
I guess, you have just found out why the Singleton is an anti-pattern. –  toscho Mar 17 '11 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. –  rofflox Mar 18 '11 at 9:35
add comment

1 Answer

up vote 3 down vote accepted

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. :)

share|improve this answer
    
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. –  rofflox Mar 22 '11 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 ;). –  rofflox Mar 31 '11 at 19:42
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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