13

Is there some documentation somewhere that explains what is the life cycle of the plugins?

I'm starting a new plugin with OOP style, and I just found out that my main class is being instanciated a lot (thanks to Xdebug and Netbeans).
I wonder why, and it annoys me because I'm instanciating a Dropbox-API object, and I really didn't think WordPress would just instanciate my main class that much.

I haven't found anything related to the plugins life cycle in the Codex nor on Google.

6
  • And here, have you searched here? :)
    – brasofilo
    Jul 24, 2012 at 14:42
  • 20
    YouPorn can always define your class as a singleton stackoverflow.com/questions/203336/…
    – Bainternet
    Jul 24, 2012 at 15:10
  • 1
    thanks. I didn't thought about 'best practices'. I read a lot of things on the Codex, including Coding Guidelines but it's not here.. Will try the singleton then, but still, I find it strange that the plugin php is called multiple times.. No ? Bainternet be careful with your autocomplete :) Jul 24, 2012 at 16:04
  • brasofilo, making a singleton would help but doesn't answer the question which is : why is the code ran multiple times inside my plugin ? The OO class in the URL you linked is doing exactly what I do Jul 24, 2012 at 16:09
  • 2
    Just had to +1 the question. Just for the comment and upvotes :D
    – kaiser
    Nov 3, 2012 at 1:15

2 Answers 2

3

I'm starting a new plugin with OOP style

What does 'OOP style' means for you? Wrapping all your functions with a class statement? Then you doing it wrong. You missuse the class as namespace.

and I just found out that my main class is being instanciated a lot

Huh?

class Foo
{
  public function __construct() {
    // assuming your wp-content dir is writeable
    $filename = sprintf( WP_CONTENT_DIR . '/dummyfile-%d.txt', time() );
    $handle = fopen( $filename, 'w' );
    if ( $handle ) {
      fputs( $handle, '-' );
      fclose( $handle );
    }
  }
}

add_action( 'plugins_loaded', function() { new Foo(); } );

Try it and count the number of files created. If i try it out, there is one file created for each page request. This means, only one instance of the Foo class for each page request.

Let's try a action call

class Foo
{
    public function __construct() {

        $this->write_file( 'in_constructor' );
        add_action( 'init', array( $this, 'action_test' ), 10, 0 );

    }

    public function action_test() {

        $this->write_file( 'in_method_with_action_call' );

    }

    public function write_file( $filename ) {

      // assuming your wp-content dir is writeable
      $counter = 1;
      $fname = sprintf( WP_CONTENT_DIR . '/%s-%d.txt', $filename, $counter );

      if ( file_exists( $fname ) ) {
        preg_match( '/(\d)\.txt/is', $fname, $match );
          if ( isset( $match[1] ) ) {
              $counter = (int) $match[1] + 1;
              $fname = sprintf( WP_CONTENT_DIR . '/%s-%d.txt', $filename, $counter );
          }
      }

      $handle = fopen( $fname, 'a+' );
      if ( $handle ) {
          fputs( $handle, '-' );
          fclose( $handle );
      } else {
          throw new Exception( "Cannot open file {$fname} for writing" );
      }

    }
}

add_action( 'plugins_loaded', function() { new Foo(); } );

If I look in my wp-content dir, I found two files. No more. One file is created when the class instance is created. And one is created when the action call is done.

OK, let's do some stupid things with our instance. Remove the add_action( 'plugins_loaded', .. ) and add this code instead:

function bar( $foo ) {

    $baz = $foo;
    return $baz;
}

$f = new Foo();
$GLOBALS['foo'] = $f;

$f2 = $f;
$f3 = &$f;

$f4 = bar( $f2 );
$f5 = bar( $f3 );

How many files do you expect? I expect two. One from the constructor, one from the method.

A new instance is created only when the new operator is used.

add_action( 'plugins_loaded', 'new_foo', 10, 0 );

function new_foo() {
    // first instance
    new Foo();
}

function bar( $foo ) {
    $baz = $foo;
    return $baz;
}

// second instance here!!
$f = new Foo();
$GLOBALS['foo'] = $f;

$f2 = $f;
$f3 = &$f;

$f4 = bar( $f2 );
$f5 = bar( $f3 );

Now I count four files. Two from the constructor and two from the method. This is because WordPress first include the plugin and then do the action hook plugins_loaded.

Best practice is to use the action hook plugins_loaded instead of creating an instance out of a function because, if the plugin file is included anywhere (e.g. in another file of your plugin), a new instance of the class is created everytime the file is included. The action hook plugins_loaded is done only once for every page request.

0

What might happen is that you pass a copy of you class to a filter or action. For example, if you want to directly modify class variables inside a hook or filter you should also pass the hook by reference

add_action("some_action",array(&$this,"somefunction"))

instead of

add_action("some_action",array($this,"somefunction"))

As is mentioned by bainternet you can also use a singleton pattern to make sure that a specific object is instanciated only once (further calls return the reference to that object).

You could also consider making some functions static (by giving them the static keyword. This is usually done to 'helper'-like functions which don't interact with the rest of the class. Static methods can be called without instanciating a class.

You can also pass static functions to an action/filter:

add_action("some_action",array("ClassName","Method"))

I also checked http://codex.wordpress.org/Plugin_API/Action_Reference and found that plugins can only be loaded at two stages in the request (muplugins_loaded and plugins_loaded).

2
  • 3
    When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object. from the PHP manual. In an action call or filter, the class is send as argument. Since PHP5 there is no need to pass it as reference.
    – Ralf912
    Apr 25, 2013 at 18:53
  • I stand corrected
    – Arevico
    Apr 25, 2013 at 19:59

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.