在抽象的PHP类中返回“self”类型

时间:2017-06-28 13:04:38

标签: php inheritance phpstorm late-static-binding

PHP 7.1

我目前正在尝试创建一个抽象类来提供和定义并部分实现其子类的功能。

这里我使用以下构造:

abstract class Parent {

    public static function fromDB(string $name = '') {
        $instance = new static();
        if (!empty($name)) {
            $instance->setName($name)->read();
        }
        return $instance;
    }

    public abstract function read();

    public abstract function setName(string $name): self;

}

这里PHP似乎理解setName($name)返回类型为Parent的Object,但是PhpStorm表示无法在结果上调用read(),这可能是预期的结果。

  

错误消息:在主题类中找不到引用的方法。

我不确定这是PHP或PhpStorm中的错误,或者更有可能的是,我不理解我在做什么......

我已经阅读了Late static binding和以下问题,其中部分讨论了这个问题,但我无法弄清楚如何修复它:

感谢您的时间和帮助。

编辑:如下所示,我正在尝试在以下子类中实现:

public function setName(string $name = null): user {...}

这显然不适用于self返回,但(IMO应该)与static一起使用,这是禁止的。

4 个答案:

答案 0 :(得分:4)

您的代码示例在 PhpStorm 2017.2 (目前处于EAP阶段)中看起来不错,但在2017.1.4中显示警告。

enter image description here

很可能它是由WI-33991或其中一张相关的门票修复的。

你可能会得到&从这里开始尝试2017.2 EAP版本:http://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Early+Access+Program

它具有30天的许可证,可以与当前版本并行运行(IDE范围的设置存储在不同的文件夹中)。

答案 1 :(得分:1)

self始终引用其所在的类 never children classes 。因此,当Parent说要返回:self时,它期望您创建一个返回Parent实例的函数。您需要做的是让您的子类声明它直接执行此操作。我们声明我们将直接返回setName类,而不是声明孩子的:self将返回ChildParent的实例)。 PHP认为这完全有效(Child毕竟是Parent的实例)

我们不能在此使用:static,因为static是类定义中的保留字

abstract class ParentTest {

    public static function fromDB(string $name = '') {
        $instance = new static();
        if (!empty($name)) {
            $instance->setName($name)->read();
        }
        return $instance;
    }

    public abstract function read();

    public abstract function setName(string $name): self;

}

class Child extends ParentTest {
    public function read() {

    }

    public function setName(string $name) :ParentTest {
        return $this;
    }
}

$child = new Child();

以上代码runs without error

答案 2 :(得分:0)

恕我直言,有一种智能的SOLID方法来使用界面。 甚至应该由第三方使用的库也需要它。

因此,我们只需在所有父类中将接口名称设置为类型,而不是'self',然后继续为孩子使用'self'。

<?php
interface EntityInterface 
{
    public function setName(string $name): EntityInterface;
}

abstract class ParentTest implements EntityInterface 
{

    public abstract function read();

    public abstract function setName(string $name): EntityInterface;

}

class Child extends ParentTest 
{
    
    private string $name = '';
    
    public function read(): string 
    {
        return $this->name;
    }

    public function setName(string $name): self 
    {
        $this->name = $name;
        return $this;
    }
}

$child = new Child();
echo $child->setName('hello')->read();

答案 3 :(得分:-1)

尝试更改以返回静态,静态应指示您正在返回扩展类,这可能会删除错误。

这是猜测工作,但值得一试。

public abstract function setName(string $name): static;

编辑:好的,我不认为会这样做,你能提供更多关于这个问题的信息吗?阅读的目的是什么? fromDb?等?