未调用由trait定义的构造函数/析构函数

时间:2013-01-04 12:37:29

标签: php traits

如何启动trait定义的构造函数和析构函数以及类的构造函数和析构函数。例如,

trait Audit
{
    public function __construct()
    {
        parent::__construct(); // Doesn't work...

        $this->_name = __CLASS__;

        $this->AuditAction('Started');
    }

    public function __destruct()
    {
        parent::__destruct(); // Doesn't work...

        $this->AuditAction('Ended');

        echo $this->_log;        
    }

    public function AuditAction($n)
    {
        $this->_log .= $this->GetCurrentTimeStamp() . ' ' . $this->_name . ": $n" . PHP_EOL;
    }

    private function GetCurrentTimeStamp()
    {
        return (new DateTime())->format('[Y-m-d H:i:s]');
    }

    private $_name, $_log = '';
}

class C
{
    use Audit;

    public function __construct()
    {

    }

    public function __destruct()
    {

    }
}

$c = new C();

我应该得到几行文本但是我没有得到,因为C类的构造函数被明确地调用了。有没有办法实现这个目标?

3 个答案:

答案 0 :(得分:5)

构造类时,C的构造函数和析构函数优先于trait构造函数和析构函数:

  

来自基类的继承成员被Trait插入的成员覆盖。 优先顺序是当前类的成员覆盖Trait方法,这些方法将覆盖继承的方法。

来源:http://php.net/traits

换句话说,从C中删除空构造函数和析构函数,将使用trait的构造函数和析构函数。没有办法使用C和traits,构造函数和析构函数来完成这项工作,因为traits不像常规继承那样工作。

一般情况下,我会建议不要让Traits拥有自己的构造函数或析构函数,因为你无法实例化Traits。您从具有特征的类实例化,该类应该处于控制之中。考虑在特征中添加onCreate()onDestroy()方法,并在C上使用相应的魔术方法调用它们。您可以通过在C中对特征__construct进行别名来实现相同的效果,但我认为这样可以解决这个问题。

答案 1 :(得分:3)

添加Aeremdir的答案:来自基类和多个特征的继承构造函数......

<?php
  trait T1 {
    public function __construct() {
      $this->someval |= 0b0001;
      echo "T1::__construct() done\n";
    }
  }

  trait T2 {
    public function __construct() {
      $this->someval |= 0b0010;
      echo "T2::__construct() done\n";
    }
  }

  class C1 {
    protected $someval;

    public function __construct() {
      $this->someval = 0b10000000;
      echo "C1::__construct() done\n";
    }
  }

  class C2 extends C1 {
    use T1, T2 {
      T1::__construct as private T1__construct;
      T2::__construct as private T2__construct;
    }

    public function __construct() {
      parent::__construct();
      $this->T1__construct();
      $this->T2__construct();

      $this->someval |= 0b00100000;
      echo "C2::__construct() done\n";
    }

    public function someval() {
      $str = base_convert($this->someval, 10, 2);
      $len = strlen($str);
      if($len < 8)
          $str = str_repeat('0', 8 - $len) . $str;

      return '0b' . $str;
    }
  }

  $v1 = new C2();
  echo $v1->someval();
?>

在PHP 7.0.5下,此代码导致...

  

C1 :: __ construct()完成
  T1 :: __ construct()完成
  T2 :: __ construct()完成了   C2 :: __ construct()完成了
  0b10100011

答案 2 :(得分:2)

您必须为Trait的方法定义自定义名称。然后你可以从你的班级调用这些方法。

由于该类的方法会覆盖Trait的方法,您必须为Trait的方法分配不同的名称:

class C
{
    use Audit {
        Audit::__construct as auditConstruct;
        Audit::__destruct as auditDestruct;
    }

    public function __construct()
    {
         $this->auditConstruct();
    }

    public function __destruct()
    {
         $this->auditDestruct();
    }
}