未捕获的错误:使用__callStatic时不在对象上下文中时使用$ this

时间:2019-11-18 09:52:25

标签: php laravel class

我正在尝试使其能够使用__callStatic静态调用非静态方法,但我一直收到此错误。我知道这是有可能的,因为某些框架(例如Laravel)可以做到这一点,但是我似乎无法自己做到。

  

致命错误:未捕获错误:未在对象上下文中使用$ this   在Output.php:18中堆栈跟踪:   index.php(4):输出:: prepare()   在第14行的Output.php中抛出1个{main}

index.php

$output = Output::prepare();

Output.php

class Output
{
    public static function __callStatic($method, $args)
    {
        if ($method == 'prepare') {
            $obj = new static();
            return $obj->$method(...$args);
        }
    }

    public function prepare()
    {
        // (!) Uncaught Error: Using $this when not in object context
        if ($this->hasItems()) {
            return print_r($_POST, true);
        }
    }

    public function hasItems()
    {
        return true;
    }
}

4 个答案:

答案 0 :(得分:2)

  

“ {__callStatic()在静态上下文中调用不可访问方法时触发。”

您的方法prepare通过可见性可以可访问。如果要使用prepare,则需要调整__callStatic方法的可见性:

protected function prepare()

您的错误听起来更像是您将prepare声明为静态函数:

public static function prepare()

代替诸如以下的非静态方法

public function prepare()

如果您的方法是非静态的,您将收到类似以下内容的信息:

  

非静态方法Output :: prepare()不应静态调用...

PHP Manual - OOP - Magic Methods - __callStatic

答案 1 :(得分:2)

除非在@lagbox所说的情况下删除对方法的可见性,否则不能在同一类上使用该技巧。否则,PHP将直接调用prepare()方法,而不会通过__callStatic()。(在您的情况下,它会导致$this错误,并警告您静态使用公共方法)

class Output
{
    public static function __callStatic($method, $args)
    {
        if ($method == 'prepare') {
            $obj = new static();
            return $obj->$method(...$args);
        }
    }

    private function prepare()//or protected to remove visibility and force the call for __callStatic()
    {
        if ($this->hasItems()) {
            return print_r($_POST, true);
        }
    }

    public function hasItems()
    {
        return true;
    }
}

如果要使用Facade技巧,则需要将静态调用转发到另一个类(可以向第二个类发送一些上下文以使其对Output类是唯一的)

class Output
{
    public static function __callStatic($method, $args)
    {
        if (!method_exists(self::class,$method)) {
            return (new Forward('output'))->$method(...$args);
        }
    }
}

class Forward
{
    private $context;

    public function __construct($context = null)
    {
        $this->context = $context;
    }

    public function prepare()
    {
        if ($this->hasItems()) {
            return print_r($_POST, true);
        }
    }

    public function hasItems()
    {
        return true;
    }
}

PS:laravel使用此特征在模型上Illuminate\Support\Traits\ForwardsCalls完成。

protected function forwardCallTo($object, $method, $parameters)
{
    try {
        return $object->{$method}(...$parameters);
    } catch (Error | BadMethodCallException $e) {
        $pattern = '~^Call to undefined method (?P<class>[^:]+)::(?P<method>[^\(]+)\(\)$~';

        if (! preg_match($pattern, $e->getMessage(), $matches)) {
            throw $e;
        }

        if ($matches['class'] != get_class($object) ||
            $matches['method'] != $method) {
            throw $e;
        }

        static::throwBadMethodCallException($method);
    }
}

答案 2 :(得分:1)

  在静态上下文中调用不可访问的方法时,会触发

__ callStatic()。

您尝试使用Output::prepare()。魔术方法__callStatic无法运行。因为,您一直使用方法prepare,并且运行方法prepare而不是__callStatic。引发错误时:

  

致命错误:未捕获错误:在Output.php的对象上下文中未使用$ this

如果您在Laravel中使用类似的工具。供参考的示例:


<?php

class Output
{
    public static function __callStatic($method, $args)
    {
        if ($method == 'prepare') {
            $obj = new Fix;
            return $obj->$method(...$args);
        }
    }
}

class Fix 
{

    public function prepare()
    {
        if ($this->hasItems()) {
            echo "Prepare";
        }
    }

    public function hasItems()
    {
        return true;
    }
}

$output = Output::prepare();

或特定:

<?php
class OutputFacade extends Facade{

    protected static function getClass()
    {
        return new Output();   
    }
}
abstract class Facade
{
    public static function __callStatic($method, $args)
    {
        $instance = static::getClass();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }
}

class Output 
{

    public function prepare()
    {
        if ($this->hasItems()) {
            echo "Prepare";
        }
    }

    public function hasItems()
    {
        return true;
    }
}

$output = OutputFacade::prepare();

注意:我的英语不好,希望你能理解

答案 3 :(得分:0)

Output类中的方法prepare不是static。您可以使用$this->来调用它,这只是一种非静态方法,可以调用prepareOutput来调用Use Output,然后您可以说{{1} },然后$output = new Output。如果要将其用作$output->prepare(),则必须将Output::prepare()类中的方法更改为Output

希望有帮助