【问题标题】:Implement type hinting 'parent' in interface throws an error在接口中实现类型提示“父级”会引发错误
【发布时间】:2019-11-12 09:30:55
【问题描述】:

可以在界面中输入提示self

interface I {
    public function instanceOfSelf(self $object);
}

class A implements I {
    private function printBool(bool $b) {
        echo ($b ? 'true' : 'false') . "\n";
    }

    public function instanceOfSelf(I $object) {
        $this->printBool($object instanceof I);
    }                        
}

$a = new A;
$a->instanceOfSelf($a); // true

也可以在界面中输入提示parent,这意味着下面的代码不会产生错误:

interface I1 {}

interface I2 extends I1 {
    public function instanceOfSelf(self $object);

    public function instanceOfParent(parent $object);
}

但是,当根据I2::instanceOfParent 提示I1 时会抛出错误:

// Duplication for completion...
interface I1 {}
interface I2 extends I1 {
    public function instanceOfSelf(self $object);

    public function instanceOfParent(parent $object);
}

class A implements I1 {}

class B implements I2 {
    private function printBool(bool $b) {
        echo ($b ? 'true' : 'false') . "\n";
    }

    public function instanceOfSelf(I2 $object) {
        $this->printBool($object instanceof I2);
    }

    public function instanceOfParent(I1 $object) {
        $this->printBool($object instanceof I1);
    }                        
}

$a = new A;
$b = new B;

$b->instanceOfSelf($b);   // true
$b->instanceOfParent($a); // true
$b->instanceOfParent($b); // true

这会产生以下错误(PHP 5.6.30、7.3.3、7.4.0):

Fatal error: Declaration of B::instanceOfParent(I1 $object) must be compatible with I2::instanceOfParent(parent $object)

  1. 那么如果I1 不是I2 的父级,那么谁是?

  2. 这是一个已知的错误,可以在界面中键入提示parent 而无法实现此功能?

【问题讨论】:

    标签: php inheritance interface php-7 type-hinting


    【解决方案1】:

    PHP 7.4 will thrown new deprecation error message 如果在没有父类型的地方使用了parent 伪类型。接口就是其中一个例子。

    When I execute your code I get 2 errors in PHP 7.4:

    不推荐使用:当当前类范围在第 8 行的 /in/tOSug 中没有父级时,不能使用“父级”

    致命错误:无法检查 B::instanceOfParent(I1 $object) 和 I2::instanceOfParent(parent $object) 之间的兼容性,因为第 22 行的 /in/tOSug 中没有类父级

    这表明问题出在哪里。您不能在界面中使用parent
    您可以通过将parent 替换为接口的实际名称来解决此问题:

    // Duplication for completion...
    interface I1 {}
    interface I2 extends I1 {
        public function instanceOfSelf(self $object);
    
        public function instanceOfParent(I1 $object);
    }
    
    class A implements I1 {}
    
    class B implements I2 {
        private function printBool(bool $b) {
            echo ($b ? 'true' : 'false') . "\n";
        }
    
        public function instanceOfSelf(I2 $object) {
            $this->printBool($object instanceof I2);
        }
    
        public function instanceOfParent(I1 $object) {
            $this->printBool($object instanceof I1);
        }                        
    }
    
    $a = new A;
    $b = new B;
    
    $b->instanceOfSelf($b);   // true
    $b->instanceOfParent($a); // true
    $b->instanceOfParent($b); // true
    

    Type declarations 下的 PHP 手册中没有记录使用 parent 的足够有趣的类型提示

    解释为什么代码的行为不符合您的预期。

    关键字parent 始终指代父类,或者换句话说,您所扩展的类。在您的示例中,B 类没有父级。它只实现了一个接口。

    class B  {
        public function amIanOrphan() {
            var_dump(parent::class);
        }             
    }
    
    $b = new B; 
    $b->amIanOrphan();
    

    这段代码会报错:

    致命错误:未捕获的错误:当前类范围没有父级时无法使用“父级”

    接口本身不是类。接口只告诉你类有哪些方法。
    这段代码和上面一模一样:

    interface I1 {
        public function amIanOrphan();
    }
    
    interface I2 extends I1 {
    }
    
    class B implements I2 {
        public function amIanOrphan() {
            var_dump(parent::class);
        }
    }
    

    接口从另一个接口扩展而来,但类本身仍然没有父类。上面的代码仍然会抛出错误,因为 B 没有父级,同样的逻辑也适用于类型提示。

    【讨论】:

    • 谢谢,我没有收到“已弃用”警告,因为我使用了 wandbox。
    猜你喜欢
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 2010-09-30
    • 2017-01-29
    • 1970-01-01
    相关资源
    最近更新 更多