PHP中的多态静态和非静态函数

时间:2018-03-31 15:40:17

标签: php polymorphism static-methods

我想在PHP中创建一个简单的Path类。我决定使用一些类似多态的机制来实现它,但我发现没有办法同时为它们做这些:静态和非静态函数。您是否有任何想法如何以优雅的方式实现absolute()功能?

class Path {

    private $path = '';

    // Some code here [...]

    public function absoulte() {
        return "http://$_SERVER[HTTP_HOST]$this->path";
    }

    public static function absoulte($path) {
        return "http://$_SERVER[HTTP_HOST]$path";
    }
}

3 个答案:

答案 0 :(得分:1)

您可以尝试使用“__callStatic”。如果你在这个类上调用任何静态函数,它将触发。 “$ name”将是方法名称,“$ arguments”是传递的任何参数。 :d

class Path {

    private $path = '';

    // Some code here [...]

    public function absoulte() {
        return "http://$_SERVER[HTTP_HOST]$this->path";
    }

   public static function __callStatic($name,$arguments) {
       if ($name == "absoulte") {  return "http://$_SERVER[HTTP_HOST]$arguments"; }
   }
}

答案 1 :(得分:1)

好的,我试一试,看看它对你有帮助。 :)

我认为实际上有很多方法可以实现您所描述的公共界面,尽管它们在编码和维护方面似乎都相当复杂。因此,如果不是真的有必要,我的建议是不要走这条路。我会举一些例子......

可能的解决方案1:使用__call__callStatic

我们可以简单地使用__call__callStatic作为我们方法的代理,并使用稍微不同的参数调用实际方法。顶部的PhpDoc应该支持IDE了解这里发生了什么。

/**
 * @method string absolute()
 * @method static string absolute(string $path)
 */
class Path
{
    protected $path;

    public function __construct(string $path)
    {
        $this->path = $path;
    }

    public function __call(string $name, array $args)
    {
        if ($name === 'absolute') {
            return self::getAbsolutePath($this->path);
        }

        // ... other functions ...
    }

    public function __callStatic(string $name, array $args)
    {
        if ($name === 'absolute' && count($args) >= 1) {
            return self::getAbsolutePath($args[0]);
        }

        // ... other functions ...
    }

    private static function getAbsolutePath(string $path): string
    {
        return "http://{$_SERVER[HTTP_HOST]}{$path}";
    }
}

可能的解决方案2:对执行环境做出反应

因为我们既可以以静态方式也可以以非静态方式访问PHP中的方法,我们只需使用这些信息来返回正确的结果。

/**
 * @method string absolute()
 * @method static string absolute(string $path)
 */
class Path
{
    protected $path;

    public function __construct(string $path)
    {
        $this->path = $path;
    }

    public function absolute(?string $path): string
    {
        if (isset($this) && $this instanceof self) {
            $path = $this->path;
        }

        return "http://{$_SERVER[HTTP_HOST]}{$path}";
    }
}

其他解决方案

我认为还有其他方法可以实现这一点,可能是使用代理类左右。但正确的做法也取决于我们迄今为止看到的其他要求。因为一个参数$path很容易处理,但是你的类越复杂,实现不同场景的工作就越多。

总结一下,我想了解上面的评论:如果有办法解决问题,尽量不要实施两次。你会发现自己处于以后在多个地方寻找虫子的情况。因此,最好的想法就是让两个不同的接口具有通用实现。它实际上甚至可以有意义,因为相同的方法名称在静态环境和非静态环境中都不一定有意义。所以考虑使用这样的东西:

/**
 * @method string absolute()
 * @method static string absolute(string $path)
 */
class Path
{
    protected $path;

    public function __construct(string $path)
    {
        $this->path = $path;
    }

    public function getAbsolutePath(): string
    {
        return self::absolute($this->path);
    }

    public static function absolute(string $path): string
    {
        return "http://{$_SERVER[HTTP_HOST]}{$path}";
    }
}

答案 2 :(得分:1)

它已经解决了,但也许可以帮助其他人。以下是使用func_num_args()func_get_arg()函数的另一种方法。

class Path {

    private $path = '';

    // ...

    public function absolute() {
        switch (func_num_args()) {
            case 0: return "http://" . $_SERVER[HTTP_HOST] . $this->path;
            case 1: return "http://" . $_SERVER[HTTP_HOST] . func_get_arg(0);
            default: trigger_error("Invalid number of arguments", E_USER_ERROR);
        }
    }
}