首页 > 解决方案 > 在 php 8.x 中使用父函数访问子属性的问题

问题描述

我正在制作一个框架来制作自己的服务器,为此我实现了许多类,其中一个是名为 model 的类,它是支持其他特定模型的通用父类。这是类模型的构造:

namespace app\core;
use app\models\RegisterModel;
abstract class Model
{ 

  /*just definition of generic properties and rules to the model*/


  public array $errors = [];
  public const RULE_REQUIRED = 'required';
  public const RULE_EMAIL = 'email';
  public const RULE_MIN = 'min';
  public const RULE_MAX = 'max';
  public const RULE_MATCH = 'match';
  
  /*the purpouse of this function is load data to the object, when i save the data this way it works well*/

  public function loadData($data){
  foreach($data as $key => $value){
      if (property_exists($this, $key)){
        $this->{$key} = $value;
      }
    };
  }

/这是给我带来麻烦的功能/

公共函数验证(){

    foreach ($this->rules() as $attibute => $rules) {
      // code...
      $value = $this->{$attibute};
      foreach ($rules as $rule) {
        // code...
          $ruleName = $rule;
          if (!is_string($ruleName)) {
            // code...
            $ruleName = $rule[0];
          }
          if ($ruleName == self::RULE_REQUIRED && !$value){
               $this->addError($attribute, self::RULE_REQUIRED);
          }

      }
    }
  }

这是子班

namespace app\models;
use app\core\Model;
class RegisterModel extends Model
{
  public string $firstname;
  public string $lastname;
  public string $email;
  public string $password;
  public string $confirmPassword;
  /*los nombres tienen que coincidir con los deldocumento register.php*/
  public function register(){
    return true;
  }
  public function rules(): array{
    return [
        'firstname'=> [self::RULE_REQUIRED],
        'lastname'=> [self::RULE_REQUIRED],
        'email'=> [self::RULE_REQUIRED, self::RULE_EMAIL],
        'password'=> [self::RULE_REQUIRED, [self::RULE_MIN, 'min'=>8], [self::RULE_MAX, 'max'=>24]],
        'password'=> [self::RULE_REQUIRED, [self::RULE_MATCH, 'match'=>'password']]
    ];
  }

}

当我创建该类的实例(我们称之为 ChildInstance)并加载 $firstname、$lastname、$email、$password、$confirmpasword 的信息,然后在 ChildInstance 上使用 var_dump 时,我可以看到我在此实例上加载的信息。但是当我使用函数 validate (函数 validate 和 loadData 都属于父类)时,它会引发此错误:

 Uncaught Error: Typed property app\models\RegisterModel::$firstname must not be accessed before initialization 

我已经通过继承解决了这个问题,但是我无法使用这种方法解决它,为什么无法使用父类的函数访问存储的信息?谢谢你

标签: phpinheritancephp-8

解决方案


发生这种情况是因为类型化的属性,即public string $firstname.

当您定义属性的类型,但不给它一个默认值时,它uninitialized在 PHP 引擎盖下有一个状态。这个错误本质上是在说:你在给它一个值之前试图访问一个类型化的属性。

借用 madewithlove 的一个例子这将导致同样的错误:

class User
{
    private int $id;
    private string $username;

    public function __construct(int $id)
    {
        $this->id = $id;
    }

    public function getUsername(): string
    {
        return $this->username;
    }
}

$user = new User(1);
echo $user->getUsername();

请注意,我们从未给出$username值,也没有在属性上设置默认值。

我不确定最好的解决方案是什么;这取决于您的共享Model的设计用途、子实例的实例化方式等。设置默认属性值是一种选择。通过反射实例化模型和属性值可能是另一回事。


推荐阅读