Pages

Wednesday, March 26, 2014

Method Dispatch

Method Dispatch 

There are differences between what Hack allows and what PHP (both HHVM and Zend) allows at runtime with respect to calling static and instance methods. Keeping them all straight can be confusing. Below are matrices that hopefully alleviate the pain of trying to remember the differences. The first matrix are calls from a class instance method. The second matrix represent calls from a class static method.
The code associated with the class instance method matrix is represented here:
<?hh
class {
  public function 
f1(): void {
    echo 
"A.f1()\n";
  }
  public static function 
f2(): void {
    echo 
"A.f2()\n";
  }
}

class 
extends {
  public function 
f1(): void {
    echo 
"B.f1()\n";
  }
  public static function 
f2(): void {
    echo 
"B.f2()\n";
  }
  public function 
test(): void {
    
$a = new A();
    
$c = new C();

    
A::f1();
    
$a->f1();
    
$a::f1();
    
A::f2();
    
$a->f2();
    
$a::f2();

    
self::f1();
    
B::f1();
    
self::f2();
    
B::f2();

    
C::f3();
    
$c->f3();
    
$c::f3();
    
C::f4();
    
$c->f4();
    
$c::f4();

    
parent::f1();
    
parent::f2();

    static::
f1();
    static::
f2();

    
$this->f1();
    
$this->f2();
  }
}

class 
{
  public function 
f3(): void {
    echo 
"C.f3()\n";
  }
  public static function 
f4(): void {
    echo 
"C.f4()\n";
  }
}

function 
main() {
  
$b = new B();
  
$b->test();
}
main();
And here is the output of the calls made in the instance test() function of class B.
Function Call
Zend Runtime Output
HHVM Runtime Output
Hack Output (partial)
Hack Output (strict)
A::f1();
A.f1()
A.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
$a->f1();
A.f1()
A.f1()
No error
No error
$a::f1();
A.f1()
A.f1()
No error
Don't use dynamic classes
A::f2();
A.f2()
A.f2()
No error
No error
$a->f2();
A.f2()
A.f2()
The method f2 is undefined in an object of type A. The closest thing isf2 but it's a static method.
The method f2 is undefined in an object of type A. The closest thing isf2 but it's a static method.
$a::f2();
A.f2()
A.f2()
No error
Don't use dynamic classes
self::f1();
B.f1()
B.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
B::f1();
B.f1()
B.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
self::f2();
B.f2()
B.f2()
No error
No error
B::f2();
B.f2()
B.f2()
No error
No error
C::f3();
C.f3()
C.f3()
Could not find static method f3. The closest thing is f3 but it's not a static method.
Could not find static method f3. The closest thing is f3 but it's not a static method.
$c->f3();
C.f3()
C.f3()
No error
No error
$c::f3();
C.f3()
C.f3()
No error
Don't use dynamic classes
C::f4();
C.f4()
C.f4()
No error
No error
$c->f4();
C.f4()
C.f4()
The method f4 is undefined in an object of type C. The closest thing isf4 but it's a static method.
The method f4 is undefined in an object of type C. The closest thing isf4 but it's a static method.
$c::f4();
C.f4()
C.f4()
No error
Don't use dynamic classes
parent::f1();
A.f1()
A.f1()
No error
No error
parent::f2();
A.f2()
A.f2()
The method f2 is undefined in an object of type A. The closest thing isf2 but it's a static method.
The method f2is undefine in an object of type A. The closest thing isf2 but it's a static method.
static::f1();
B.f1()
B.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
static::f2();
B.f2()
B.f2()
No error
No error
$this->f1();
B.f1()
B.f1()
No error
No error
$this->f2();
B.f2()
B.f2()
The method f2is undefined in an object of type B. The closest thing isf2 but it's a static method.
The method f2is undefined in an object of type B. The closest thing isf2 but it's a static method.
The code associated with the class static method matrix is represented here:
<?hh
class {
  public function 
f1(): void {
    echo 
"A.f1()\n";
  }
  public static function 
f2(): void {
    echo 
"A.f2()\n";
  }
}

class 
extends {
  public function 
f1(): void {
    echo 
"B.f1()\n";
  }
  public static function 
f2(): void {
    echo 
"B.f2()\n";
  }

  public static function 
stest(): void {
    
$a = new A();
    
$c = new C();

    
A::f1();
    
$a->f1();
    
$a::f1();
    
A::f2();
    
$a->f2();
    
$a::f2();

    
self::f1();
    
B::f1();
    
self::f2();
    
B::f2();

    
C::f3();
    
$c->f3();
    
$c::f3();
    
C::f4();
    
$c->f4();
    
$c::f4();

    
parent::f1();
    
parent::f2();

    static::
f1();
    static::
f2();

    
$this->f1();
    
$this->f2();
  }
}

class 
{
  public function 
f3(): void {
    echo 
"C.f3()\n";
  }
  public static function 
f4(): void {
    echo 
"C.f4()\n";
  }
}

function 
main() {
  
B::stest();
}
main();
And here is the output of the calls made in the static stest() function of class B.
Function Call
Zend Runtime Ouput
HHVM Runtime Output
Hack Output (partial)
Hack Output (strict)
A::f1();
A.f1()
A.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
$a->f1();
A.f1()
A.f1()
No error
No error
$a::f1();
A.f1()
A.f1()
No error
Don't use dynamic classes
A::f2();
A.f2()
A.f2()
No error
No error
$a->f2();
A.f2()
A.f2()
The method f2 is undefined in an object of type A. The closest thing is f2 but it's a static method.
The method f2 is undefined in an object of type A. The closest thing is f2 but it's a static method.
$a::f2();
A.f2()
A.f2()
No error
Don't use dynamic classes
self::f1();
B.f1()
B.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
B::f1();
B.f1()
B.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
self::f2();
B.f2()
B.f2()
No error
No error
B::f2();
B.f2()
B.f2()
No error
No error
C::f3();
C.f3()
C.f3()
Could not find static method f3. The closest thing is f3 but it's not a static method.
Could not find static method f3. The closest thing is f3 but it's not a static method.
$c->f3();
C.f3()
C.f3()
No error
No error
$c::f3();
C.f3()
C.f3()
No error
Don't use dynamic classes
C::f4();
C.f4()
C.f4()
No error
No error
$c->f4();
C.f4()
C.f4()
The method f4 is undefined in an object of type C. The closest thing is f4 but it's a static method.
The method f4 is undefined in an object of type C. The closest thing is f4 but it's a static method.
$c::f4();
C.f4()
C.f4()
No error
Don't use dynamic classes
parent::f1();
A.f1()
A.f1()
No error
No error
parent::f2();
A.f2()
A.f2()
The method f2 is undefined in an object of type A. The closest thing is f2 but it's a static method.
The method f2is undefined in an object of type A. The closest thing is f2 but it's a static method.
static::f1();
B.f1()
B.f1()
Could not find static method f1. The closest thing is f1 but it's not a static method.
Could not find static method f1. The closest thing is f1 but it's not a static method.
static::f2();
B.f2()
B.f2()
No error
No error
$this->f1();
Error. Using$this when not in object context.
HipHop Fatal error:$this isnull.
Do not use $this in a static method.
Do not use $this in a static method.
$this->f2();
Error. Using$this when not in object context.
HipHop Fatal error:$this isnull.
Do not use $this in a static method.
Do not use $this in a static method.

No comments:

Post a Comment