2

I wrote some code to use a PHP library (for a product called Checkfront, but that's not important). The library defines a class that has an abstract method:

abstract protected function store($data);

and in my code I subclass it as

final protected function store($data=array()) {

In my standalone version of the code, that works fine using the implementation from some example code:

/* DUMMY Data store.  This sample stores oauth tokens in a text file...
 * This is NOT reccomened in production.  Ideally, this would be in an encryped 
 * database or other secure source.  Never expose the client_secret or access / refresh
 * tokens.
 *
 * store() is called from the parent::CheckfrontAPI when fetching or setting access tokens.  
 *
 * When an array is passed, the store should save and return the access tokens.
 * When no array is passed, it should fetch and return the stored access tokens.
 *
 * param array $data ( access_token, refresh_token, expire_token )
 * return array
 */
final protected function store($data=array()) {
    $tmp_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR. $this->tmp_file;
    if(count($data)  ) {
        file_put_contents($tmp_file,json_encode($data,true));
    } elseif(is_file($tmp_file)) {
        $data = json_decode(trim(file_get_contents($tmp_file)),true);
    }
    return $data;
}

. But when I tried to use it in a Wordpress plugin I got errors. Here's the function in Wordpress land:

final protected function store($data=array()) {
    global $wpdb;
    if (count($data)) {
        $query = "
            INSERT INTO {$wpdb->prefix}pt_store (k, v)
            VALUES      (%s, %s)
            ON DUPLICATE KEY UPDATE v=values(v)";
        foreach ($data as $k => $v) {
            $wpdb->query($wpdb->prepare($query, $k, $v));
        }
    } else {
        $data = $wpdb->get_results("
            SELECT  (k, v)
            FROM    {$wpdb->prefix}pt_store", ARRAY_A);
    }
    return $data;
}

But when I try to activate the plugin, it gives me the error:

Fatal error: Declaration of Checkfront::store() must be compatible with that of CheckfrontAPI::store() in /hsphere/local/home/[blah]/[blah].ixtrial.com/wordpress/wp-content/plugins/pt-checkfront/pt-checkfront.php on line 15

The declarations look the same to me, so what's wrong? (keep in mind that this is my first time writing PHP so don't overlook the possibility that I'm being stupid here.)

Paul Tomblin
  • 179,021
  • 58
  • 319
  • 408

3 Answers3

4

Under PHP 5.2 and earlier, an optional parameter will cause the signature to be considered different. You can’t really work around that in a nice way, so try upgrading PHP.

’Course, it’s possible that you don’t need the default value. In that case, take it out! You can also pass null and do this:

final protected function store($data) {
    if ($data === null) $data = array();
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Hosting site, can't upgrade PHP. I was command line testing on my home computer which of course has a newer version of PHP. – Paul Tomblin Dec 22 '13 at 19:55
2

Adding =array() makes the parameter optional (see this stackoverflow question).

This changes the method signature.

Community
  • 1
  • 1
Kristoffer Sall-Storgaard
  • 10,576
  • 5
  • 36
  • 46
0

To avoid this error you need to ensure that the method signature is identical in both classes, including optional arguments.

Alter the abstract class to allow for the default array

abstract protected function store($data = array());

The PHP manual states

The signatures of the methods must match, i.e. the type hints and the number of required arguments must be the same. For example, if the child class defines an optional argument, where the abstract method's signature does not, there is no conflict in the signature.

AlexP
  • 9,906
  • 1
  • 24
  • 43
  • 3
    Your quote contradicts your answer. *“For example, if the child class defines an optional argument, where the abstract method's signature does not, there is no conflict in the signature.”* – Ry- Dec 22 '13 at 19:55