Declaration should be compatible with...
You installed a new plugin, or upgraded your DokuWiki or your hoster did a PHP update and suddenly you see warnings like these on your screen (or in your logs)?
PHP Warning:  Declaration of action_plugin_example::register(&$c) should be compatible with DokuWiki_Action_Plugin::register(Doku_Event_Handler $controller) in /data/dokuwiki/lib/plugins/example/action.php on line 99

In this post I'll try to explain what's going on, how you can diagnose and in the end even fix the problem yourself.

The Problem

To explain what exactly is this message is trying to tell you, we have to learn a bit more about the programming of DokuWiki. I'll try to keep it as simple as possible.

The message comes from the PHP interpreter. As you may know, DokuWiki and its plugins are written in a programming language called PHP. Unlike other languages it is a so called script language. This means the source code is interpreted at runtime. So when you open your DokuWiki, your web server says "hey PHP, here's some .php file, can you interpret it for me and tell me what to show to the user?"

Now PHP is an evolving software. New versions of it come with new features. And while the PHP team tries to be somewhat backward compatible, some mechanisms of the language change over time. This means PHP source code (eg. DokuWiki) needs adjustments to keep up with PHP's development. That's why an old version of DokuWiki will probably not run on a new PHP version. But also why a new DokuWiki version may require a newer PHP version than before.

Now back to the warning message. It says "Declaration ... should be compatible with [some class function]".

PHP is object oriented. This means there are constructs in the language that describe a general thing (like an "action plugin") - we call that an object. And then there can be many objects that inherit certain properties from that object. For example there can be a specific plugin, let's say the "upgrade plugin" that inherits from the general object "action plugin".

When ever an object inherits from another and changes something that was initially set up in the parent, there are some rules that need to be adhered. One of the rules is that "method signatures" have to match. A method signature is  basically a combination of a method name and the kind of parameters it accepts.

So where's the mismatch in our example above?

There is an object called action_plugin_example that inherits from an object called DokuWiki_Action_Plugin. The objects are the things before the double colons. DokuWiki_Action_Plugin is defined by the DokuWiki core, while the action_plugin_example comes from an installed plugin.

Both objects have a method called register. That's the thing after the double colons. However that method has &$c as parameter in one and Doku_Event_Handler $controller in the other call (the stuff in parentheses).

So there is a mismatch and that's what PHP complains about.

However, please note that the mismatch is not the name of the parameter ($c vs. $controller), that name does not matter at all. The problem are the & and the Doku_Event_Handler.

We're already quite deep in the PHP programming language here, but please bear with me a bit more. I'll try to keep it as simple as possible.

The & specifies that a passed parameter should be passed by reference. It's not important to understand what this means. All we need to know is that newer versions of PHP (actually since more than 10 years, but DokuWiki is older than that) will always pass objects by reference. So this & is completely superfluous here. That's why it is removed in DokuWiki core. It is not used in DokuWiki_Action_Plugin::register and thus should not be in action_plugin_example::register either.

The Doku_Event_Handler prefix is a so called type hint. It tells the PHP interpreter that there should never be anything else passed as a parameter other than an object of this Doku_Event_Handler type. This hint is mostly just that, a hint to programmers. But it is also a bit of a safe guard to avoid a programmer accidentally using the method wrong. Since it's in one object's method signature, it should also be in the other.

That's it. Nothing really complicated or grave, it's just a bit messy. PHP says "hey this is not as clean as it should be", but will continue to interpret the program. 

The Fix

Now the first way to fix the problem is to make sure the plugin in question is up-to-date.

So how do you figure out which plugin is causing the trouble?

Easy! There's more info in that warning message. At the end it gives a file name .../lib/plugins/example/action.php. The folder name right after /plugins/ tells you what plugin caused the problem. So in this case it's the (made up) example plugin.

Just open your extension manager, find the plugin in question and click "Reinstall" to absolutely make sure you have the newest version.

If you're lucky, you already fixed the problem. Be sure to repeat this for all the plugins showing the "declaration should be compatible" warning.

So what if there is no update? First and foremost you should try to contact the plugin's author. Best way to do that is opening an issue in the plugin's issue tracker if there is any. Unfortunately not all plugins are well maintained, so you may not get a response.

You can abandon the plugin for something better maintained or you can try to fix it yourself. Luckily that's quite easy in this case. After reading the lengthy description about the underlying problem, you probably have an idea how to do it already.

Just in case, here is how you do it:

  • Locate the file mentioned in the warning message on the server's file system (for a hosted wiki probably using FTP). In our case it's /data/dokuwiki/lib/plugins/example/action.php.
  • Copy the file to your local computer and maybe make a backup
  • Open the file in a UTF-8 capable text editor (do not use Word or Notepad!) I recommend Notepad++ for Windows users
  • Find the line mentioned in the error message. Line 88 in our case
  • You should find the method signature as written in the message there. That would be function register(&$c) for us.
  • Now change it so that it matches the other signature. In our case function register(Doku_Event_Handler $c). Be sure to NOT change the actual parameter name. We only care about removing the & and adding the type hint.
  • Save the file and upload it back to your wiki server, overwriting the old file

That should fix the problem for you. Repeat for all other messages of the same type.

Some Afterthought

In hindsight, I guess the introduction of a TypeHint in a such widely used API was a mistake. It wasn't really necessary. However we stuck with it for a long time now and the majority of plugins have been adjusted, so removing it again would break all those plugins again... Lesson learned, I guess.