php class OOP 使用 $this-> 问题

A.php

class A {
  protected $message;

  function __construct() {
    global $app;
    $this->message = $app->message;
  }

  public function aaa() 
  {
    return $this->message['userError_2'];
  }
  public function ccc() 
  {
    return B::bbb()
  }
  public function fff() 
  {
    return $this->message['userError'];
  }
}

B.php

class B {
  protected $message;

  function __construct() {
    global $app;
    $this->message = $app->message;
  }

  public function bbb() 
  {
    return $this->message['userError'];
  }
}

在执行 B::ccc() 出现错误

Message: Using $this when not in object context

但执行 A::fff() 是可以成功拿值的
这是什么意思?

阅读 2.5k
1 个回答

你应该使用更新 PHP 版本,并使用正确的编码方式

虽然你这代码里面存在一堆错误,但是我还是打算花一点儿时间来解答这个问题。

首先,在新版本的 PHP >=7.0 中,你的代码将无法工作。

其次,我想你举的例子还是存在问题,简单整理一下代码。

<?php
error_reporting(0);

// A
class A
{
  protected $message;
  function __construct()
  {
    global $app;
    $this->message = $app->message;
  }
  public function ccc()
  {
    var_dump('ccc');
    return B::bbb();
  }
  public function fff()
  {
    var_dump('fff');
    return $this->message['userError'];
  }
}

// B
class B
{
  protected $message;
  function __construct()
  {
    global $app;
    $this->message = $app->message;
  }
  public function bbb()
  {
    var_dump($this, 'bbb');
    return $this->message['userError'];
  }
}

现在以上面的代码为例子 如果你是在 PHP 5 和 7 中,如果无论使用 A::fff()A::ccc()、 还是 B::bbb() 都可以调用成功(运行到 var_dump,但是不能继续往下)点击这里运行测试

理论上在 PHP 4 中也可以运行成功(但是你需要删减一些代码,移除一些 PHP 4 中不支持的特性。)

因为这是一个源自 PHP 4 的问题,一直到 PHP 8 才被移除了。

而这里还隐藏着一个更加有趣的问题,查看如下代码:点击这里测试

$a = new A;
$a->ccc();

因为在 ccc 中调用 B::bbb() 方法,而又在 bbb 方法中打印了 $this 和 bbb ,但是惊奇的发现,这里的 $this 居然是指向的 $a

string(3) "ccc"
object(A)#1 (1) {
  ["message:protected"]=>
  NULL
}
string(3) "bbb"

而这段代码在 PHP 8 中将只能输出 ccc ,这是符合预期的。

但是如果稍加修改。

<?php
error_reporting(E_ALL);

// A
class A
{
  public $message;
  function __construct()
  {
    global $app;
    $this->message = $app->message;
  }
  public function ccc()
  {
    var_dump('ccc');
    return B::bbb();
  }
  public function fff()
  {
    var_dump('fff');
    return $this->message['userError'];
  }
}

// B
class B
{
  protected $message;
  function __construct()
  {
    global $app;
    $this->message = $app->message;
  }
  public function bbb()
  {
    var_dump($this, $this->message, 'bbb');
    return $this->message['userError'];
  }
}

$app = new stdClass();
$app->message = array('userError'=>'Hi');
$a = new A();

$a->ccc();

注意,修改了 A 的 $message 为 public ,并修改了 B 的 bbb 的 var_dump 部分打印了 message ,此时的 $this 属于 A

在 PHP 5.4 以前,上面的代码甚至都不会有任何错误信息,可以运行。而到了 5.4 版本,虽然可以运行,但是多了一行错误信息。

Strict Standards: Non-static method B::bbb() should not be called statically, assuming $this from incompatible context

而到了 PHP 7 ,以上代码又将不能运行,点击这里测试

首先要明确一点,就是你始终不应该以静态访问(::)的方式去调用实例方法,这在现在(PHP 8)都是错误的,即使是在之前的版本中它可以工作,但也是错误的工作,因为当你的实例方法中存在 $this 访问的时候,你的代码运行将不符合预期。

相关链接

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏