我正在尝试使其能够使用__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;
}
}
答案 0 :(得分:2)
“ {
__callStatic()
在静态上下文中调用不可访问方法时触发。”
您的方法prepare
通过可见性可以可访问。如果要使用prepare
,则需要调整__callStatic
方法的可见性:
protected function prepare()
您的错误听起来更像是您将prepare
声明为静态函数:
public static function prepare()
代替诸如以下的非静态方法
public function prepare()
如果您的方法是非静态的,您将收到类似以下内容的信息:
非静态方法Output :: prepare()不应静态调用...
答案 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->
来调用它,这只是一种非静态方法,可以调用prepare
类Output
来调用Use Output
,然后您可以说{{1} },然后$output = new Output
。如果要将其用作$output->prepare()
,则必须将Output::prepare()
类中的方法更改为Output
。
希望有帮助