【问题标题】:Private access in inheritance继承中的私有访问
【发布时间】:2018-04-21 00:15:39
【问题描述】:
class  Person {
    public  $name;
    private $age; //private access
}

class Employee extends Person{
    public $id;
    public $salary; //class property   
}

$emp = new Employee(); 
$emp->name="ABCD";
$emp->age = 30;
$emp->id=101;
$emp->salary=20000;

echo "<br/> Name : ".$emp->name;
echo "<br/> Age : ".$emp->age;

在这段代码中,子类变量$emp可以直接访问父类Person的私有成员。这不是违反私有访问规则吗?

使用父类变量时会出错,但与子类变量一起使用!!谁能解释一下为什么?

【问题讨论】:

  • 如果您 var_dump($emp) ... ["age":"Person":private]=&gt; NULL ["age"]=&gt; int(30) ... 私人 Person::age 为 NULL,但会创建一个新的公共 Employee::age 并将其设置为 30,您会看到它。
  • 出于安全原因,我永远不会直接返回属性。而是创建一个将它们吐出的方法

标签: php class inheritance private-members


【解决方案1】:

TLDR;

$emp-&gt;age = 30不调用父私有成员age,而是动态创建新的子对象属性age

说明

看起来像一个错误,不是吗?首先,让我们注释掉父级的私有成员:

<?php

class Person {
    // private $age;
}

class Employee extends Person {
}

$emp = new Employee();
$emp->age = 10;
echo $emp->age . "\n";
//out: 10

$emp-&gt;age = 10 行中,我们创建了名为age$emp 对象的新属性并将其赋值为10

当您将父母的成员定义为私有时,孩子根本看不到该成员:

<?php

class  Person {
    private $age;

    function __construct() {
        $this->age = 30;
    }

    public function printAge()
    {
        echo sprintf("Parent::age = %s\n", $this->age);
    }
}

class Employee extends Person {
    private $age;

    function __construct() {
        parent::__construct();
        $this->age = 10;
    }

    public function printAge()
    {
        echo sprintf("Employee::age = %s\n", $this->age);
        parent::printAge();
    }
}

$emp = new Employee();
$emp->printAge();

//out:
//Employee::age = 10
//Parent::age = 30

【讨论】:

    【解决方案2】:

    您正在从对象($emp)分配$emp-&gt;age = 30;

    现在,当您尝试使用对象(不是成员变量)访问任何变量时,它将允许访问并创建本地范围

    并不是说它不被视为该特定类的成员变量。

    因此,在您的示例 $emp-&gt;age 中,年龄不被视为任何类的成员变量,因为它没有在其中定义。

    如果您尝试任何不属于任何类的变量名称,您会更清楚地了解。你也会得到他们的结果。

    例如试试下面的代码:

    $emp->age_tmp = 30;
    
    echo "<br/> Age : ".$emp->age_tmp;
    

    所以问题不在于范围,而是会为该变量创建其他副本。 $emp-&gt;agePersonage 没有任何联系

    DEMO

    【讨论】:

      【解决方案3】:

      您可以定义$object = new stdClass(); 并使用语法$object-&gt;field = "value"; 赋值。

      如果超类有一个私有字段。该字段不存在于儿童中。在您的代码中,员工没有字段年龄。 $emp-&gt;age = 42; 是有效的 php 代码。

      要在 Employee 中保持年龄私密,您需要将字段设置为受保护。受保护的字段意味着它对于超类和子类都是私有的。

      人的私有领域,在孩子中不存在。

      OOP php visibility

      【讨论】:

      • 该字段存在在儿童中...只是他们通常不可见或无法访问。显着差异。
      【解决方案4】:

      在 PHP 中,您可以在代码的任何位置创建属性。变量“age”不是父类的变量。如果你愿意,你可以试试这个

      <?php
      
      class  Person {
      public  $name = "Scare";
      private $age = 30; //private access
      protected $gender = "Man";
      }
      
      class Employee extends Person{
      public $id = 20;
      public $salary; //class property   
      }
      
      $emp = new Employee(); 
      echo $emp->id;
      echo $emp->name;
      echo $emp->age;
      $emp->age = "10";
      echo $emp->age;
      echo $emp->gender;
      ?>
      

      显示的变量属于员工类,是局部变量。

      【讨论】:

        【解决方案5】:

        顺便说一句,如果您不想从实例创建私有属性$age,您不妨这样做:

        class  Person {
            public  $name;
            private $age; //private access
        
            public function __set($age, $value) {
                return false;
            }
        }
        

        __set() 是一种自动设置新属性的神奇方法。 在这种情况下,当尝试设置 $age 时它将不起作用。

        现在试试,给$age赋值。

        3v4l.org

        【讨论】:

        • 这是一个非常有价值的建议..谢谢!!
        • 与其简单地返回false,但是(这可能会让您在之后一些真正的头疼的时刻),您可能想要抛出一个异常。
        猜你喜欢
        • 1970-01-01
        • 2012-01-04
        • 2020-02-11
        • 2012-01-05
        • 1970-01-01
        • 2012-08-30
        • 2017-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多