Rich
Rich

Reputation: 15464

PHP: why is "Strict standards: Declaration of x should be compatible with y" applied to static methods?

The PHP warning, "Strict standards: Declaration of x should be compatible with y" warns you if you write code like:

class A {
  function foo($x) {
    ..
  }
}
class B extends A {
  function foo() {
    ..
  }
}

This is sensible, because an object reference like "$a" which you think is an A, may at runtime turn out to be a B, so a dynamically dispatched method call like $a->foo(3) may end up calling B::foo() with the wrong number of arguments.

My question is: why is this same warning applied to static methods, which are not dynamically dispatched?

class X {
  static function bar($x) {
    ..
  }
}
class Y extends X {
  static function bar() {
    ..
  }
}

In this example, the function Y::bar() does not override X::bar(), so there is no reason to trigger the warning, but PHP still does. Why?

Upvotes: 4

Views: 2600

Answers (3)

alt10
alt10

Reputation: 1

This warning has nothing to do with the real world. Forget the academic examples and look at a real world example. There are 1000's of LOCK manufacturers that make a door lock with a combination touchpad and a key override. Do they use 2 deadbolts - one for the combination lock and one for the key lock? NO. The deadbolt lock is abstracted to the key lock and the combination lock. That's REAL WORLD. PHP ( who will quickly reject any bug reports on this subject) want to stick their heads in the sand on this.

class abstractLock
{
    private $locked = true;
    public function unlock()
    {
       $this->locked=false;
    }
    public function lockStatus()
    {
        if($this->locked) return "Locked\n";
        else return "Unlocked\n";
    }
}

class combinationLock extends abstractLock
{
    private $combination = '32-10-21'; // combination
    public function unlock($combination)        // unlock WITH combination
    {
        if($this->combination == $combination) parent::unlock();
    }
}

class paddleLock extends abstractLock
{
    private $key = '100,70,80,30,50,90,60,40,100'; // ridge heights
    public function unlock($key)                            // unlock WITH key
    {
        if($this->key == $key) parent::unlock();
    }
} 

$lock1 = new paddleLock();
echo "paddleLock is " . $lock1->lockStatus();
$lock1->unlock('100,70,80,30,50,90,60,40,100');
echo "paddleLock is " . $lock1->lockStatus();

$lock2 = new combinationLock();
echo "combinationLock is " . $lock2->lockStatus();
$lock2->unlock('32-10-21');
echo "combinationLock is " . $lock2->lockStatus();

PHP is not willing to even discuss this issue. So all my code will contain the following to eliminate this PHP bug:

// FIX PHP's bogus warning of: PHP Warning: Declaration of * should be compatible with
if (PHP_MAJOR_VERSION >= 7) {
    set_error_handler(function ($errno, $errstr) {
       return strpos($errstr, 'Declaration of') === 0;
    }, E_WARNING);
}

Upvotes: -2

Rich
Rich

Reputation: 15464

Unlike Java, you can call static methods on an instance and they are dispatched by the runtime type of that object. So Y::bar() does in fact override X::bar() and it should be compatible.

<?php

class X {
  static function bar($x) {
    echo "X::bar() with x = $x\n";
  }
}
class Y extends X {
  static function bar() {
    echo "Y::bar()\n";
  }
}

echo "Static dispatch:\n";
X::bar(1);
Y::bar();

echo "Dynamic dispatch of a static method (surprise!):\n";
$arr = array(new X(), new Y());
foreach ($arr as $a) {
  $a::bar(1);
}

will output (run it here):

Warning: Declaration of Y::bar() should be compatible with X::bar($x) in /in/phAWB on line 12
Static dispatch:
X::bar() with x = 1
Y::bar()
Dynamic dispatch of a static method (surprise!):
X::bar() with x = 1
Y::bar()

(The equivalent code would not compile in Java.)

Upvotes: 2

Janus Troelsen
Janus Troelsen

Reputation: 21318

Just like in Java, you can call static methods on an instance too. So there is still room for confusion.

Upvotes: 4

Related Questions