闪耀的钥匙:PHP 与访问修饰符

这篇具有很好参考价值的文章主要介绍了闪耀的钥匙:PHP 与访问修饰符。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

参考

项目 描述
搜索引擎 Google 、Bing
PHP 官方文档

描述

项目 描述
PHP php-8.2.6-Win32-vs16-x64
PhpStorm PhpStorm 2023.1.1(Profession)

访问修饰符

访问修饰符

访问修饰符在面向对象编程中起着重要的作用,它们提供了 对类的属性和方法的访问级别控制。访问修饰符能够为你的程序带来以下优点:

  1. 封装性(Encapsulation)
    访问修饰符允许将类的内部实现细节隐藏起来,仅暴露必要的公有接口给外部使用。这样可以有效地封装数据和行为,提高代码的可维护性和可重用性。

  2. 访问控制(Access Control)
    通过访问修饰符,可以控制类的成员对外部的可见性和可访问性。不同的访问修饰符可以限制属性和方法的访问范围,只允许特定的代码段访问,从而提供了更好的安全性和数据保护。

PHP 与访问修饰符

PHP 支持三种访问修饰符:publicprotected 以及 private,这些修饰符所提供的访问级别具体如下。

修饰符
(Modifier)
访问级别
(Access Level)
类内部
(Inside Class)
子类
(In Subclass)
外部
(Outside Class)
public 公有 可访问 可访问 可访问
protected 受保护 可访问 可访问 不可访问
private 私有 可访问 不可访问 不可访问

注:

在 PHP 中,访问修饰符是可以省略的,但这仅仅针对于类中的方法而言。默认情况下,如果没有指定访问修饰符,方法都将被视为公有成员。

public

公有成员(使用 public 作为访问修饰符的方法或属性)在 PHP 中具有全局可见性,可以从类的内部和外部进行访问。

举个栗子

<?php
# 定义一个类,该类的所有属性与方法均为
# 公有成员。
class MyClass
{
    public $species = 'Human';
    public $hobby = 'Fantasy';
    public $secret = 'Secret';

    # 方法可以省略访问修饰符,
    # 默认使用 public 访问修饰符。
    function petPhrase()
    {
        echo 'Ni Ma';
    }

    function spy()
    {
        # 在类的内部访问公有成员
        echo $this -> secret;
    }
}


# 定义一个类,该类继承自 MyClass
# 属于 MyClass 的子类。
class Agent extends MyClass
{
    # 通过子类访问父类 MyClass 中的公有成员。
    function domesticThief()
    {
        echo $this -> secret;
    } 
}


# 实例化 MyClass
$myClass = new MyClass();

# 在类的外部访问 MyClass 类中的公有成员
echo $myClass -> species;
echo '</br>';
echo $myClass -> hobby;
echo '</br>';
$myClass -> petPhrase();
echo '</br>';
$myClass -> spy();
echo '</br>';


# 实例化 Agent
$agent = new Agent();

# 通过访问 $agent 中的 domesticThief 方法
# 间接访问 MyClass 中的公有成员 secret。
$agent -> domesticThief();
?>

上述代码定义了两个类:MyClassAgent

  • MyClass 类是一个基类,其中包含了公有属性 specieshobbysecret,以及两个方法 petPhrase()spy()MyClass 类中的方法没有显式指定访问修饰符,默认使用 public 访问修饰符。

  • Agent 类是 MyClass 类的子类,通过使用 extends 关键字继承自 MyClass。子类可以继承父类的属性和方法。

  • Agent 类中定义了一个方法 domesticThief(),该方法尝试直接访问父类 MyClass 的公有属性 secret

在代码的后半部分,通过实例化对象并调用相应的方法来演示 public 访问修饰符所提供的访问权限:

  • 首先,创建一个 MyClass 类的实例 $myClass,通过 $myClass->属性名$myClass->方法名() 的方式在类的外部访问和调用该类的公有属性和方法,并通过 spy() 方法由类的内部对 MyClass 类的 secret 属性进行访问。

  • 接着,创建一个 Agent 类的实例 $agent,调用 domesticThief() 方法。该方法尝试直接访问父类 MyClasssecret 属性。由于 secret 属性在父类中是公有的,因此子类可以访问该属性,并输出了结果。

执行效果

Human
Fantasy
Ni Ma
Secret
Secret

protected

受保护成员(使用 protected 作为访问修饰符的属性或方法)只能在定义它们的类内部或该类的子类中访问,外部无法直接访问受保护成员。

举个栗子

<?php
class MyClass
{
    public $species = "Human";
    public $hobby = "Fantasy";

    # 定义受保护成员属性
    protected $secret = "Secret";

    # 定义受保护成员方法
    protected function petPhrase()
    {
        echo 'Ni Ma';
    }

    function spy()
    {
        # 在类的内部访问受保护成员
        echo $this -> secret;
    }
}


class Agent extends MyClass
{
    # 通过子类访问父类 MyClass 中的受保护成员属性
    function domesticThief()
    {
        echo $this -> secret;
    }
}


$myClass = new MyClass();

# 在类的外部类访问 MyClass 中的公有成员
echo $myClass -> species;
echo '</br>';
echo $myClass -> hobby;
echo '</br>';
$myClass -> spy();
echo '</br>';

# 不可使用如下语句在外部访问 MyClass 中的私有成员属性
# 否则,PHP 将抛出错误信息。
// echo $myClass -> secret;
// $myClass -> petPhrase();


$agent = new Agent();

# 通过访问 $agent 中的 domesticThief 方法
# 间接访问 MyClass 中的私有成员 secret。
$agent -> domesticThief();

其中:

  • MyClass 类中的 $species$hobby 属性被声明为公有(public),因此可以从类的内部和外部访问。

  • MyClass 类中的 $secret 属性被声明为受保护(protected),这意味着它只能在定义它们的类内部和子类中访问。在类的内部,spy() 方法通过 $this->secret 访问了受保护属性。

  • MyClass 类中的 petPhrase() 方法也被声明为受保护(protected),只能在定义它们的类的内部和子类中访问。

  • Agent 类继承自 MyClass 类,因此可以访问父类中的受保护成员属性和方法。

  • Agent 类中的 domesticThief() 方法尝试直接访问父类 MyClass 的受保护属性 $secret。由于受保护属性在子类中可见,因此可以输出结果。

  • 尝试在外部访问 MyClass 类的私有成员属性 $secret 和私有成员方法 petPhrase(),会导致 PHP 抛出错误信息。

执行效果

Human
Fantasy
Secret
Secret

private

私有属性和方法只能在定义它们的类内部访问,它们对于类的外部及其子类来说是不可见的。

举个栗子

<?php
class MyClass
{
    public $species = "Human";
    public $hobby = "Fantasy";

    # 定义私有成员
    private $secret = "Secret";

    # 定义私有成员方法
    private function petPhrase()
    {
        # 在类的内部访问私有成员变量
        echo $this -> secret;
    }

    function spy()
    {
        # 在类的内部访问私有成员方法
        $this -> petPhrase();
    }
}


$myClass = new MyClass();


# 在类的外部访问 MyClass 中的公有成员
echo $myClass -> species;
echo '</br>';
echo $myClass -> hobby;
echo '</br>';

# 通过在类的外部访问 MyClass 中的公有成员
# 间接访问 MyClass 中的私有成员。
$myClass -> spy();

# 私有成员变量无法从定义它们的类的外部
# 及该类的子类中直接进行访问。否则,
# PHP 将抛出异常错误。
?>

其中:

  • MyClass 类中的 $species$hobby 属性被声明为公有(public),因此可以从类的内部和外部访问。
  • MyClass 类中的 $secret 属性被声明为私有(private),这意味着它只能在定义它们的类内部访问。在类的内部,spy() 方法通过调用私有方法 petPhrase() 来间接访问私有属性。
  • MyClass 类中的 petPhrase() 方法也被声明为私有(private),只能在定义它们的类内部访问。

执行效果

Human
Fantasy
Secret

继承中的重写规则

在 PHP 中,访问修饰符和继承之间有一些重写规则,它们决定了子类如何访问和重写父类的属性和方法。

子类对父类成员的访问权限和重写能力

访问修饰符 继承中的访问权限 重写规则
public 可以被继承 可以直接访问和重写。在子类中与父类具有相同的访问修饰符,或可以扩大为更宽松的修饰符。
protected 可以被继承 可以直接访问和重写。在子类中与父类具有相同的访问修饰符,或可以扩大为更宽松的修饰符。
private 不能被继承 无法直接访问和重写。子类可以定义具有相同名称的私有成员,但它们只是在子类中重新声明了一个新的私有成员,与父类中的私有成员没有任何关联。

可见性

在重写一个父类方法或属性时,子类的成员的可见性不能低于父类相同成员的可见性。可见性按照以下顺序从高到低:private > protected > public。这意味着子类成员可以将父类成员的可见性扩大,但不能缩小。

  • 例如,如果父类方法是 protected,子类方法可以是 protectedpublic,但不能是 private
  • 如果父类方法是 public,子类方法也可以是 protectedpublic,但不能是 private
举个栗子
未重写父类的受保护成员前
<?php
class Boss
{
    protected function target() 
    {
        echo 'Boss -> target()';
    }
}

class Boy extends Boss
{

}

$boy = new Boy();
# 由于 target() 方法在父类中为 
# 受保护成员,因此执行下述语句
# PHP 将抛出错误(在类的外部对其进行访问)。
$boy -> target();
?>
将受保护成员重写为公有成员
<?php
class Boss
{
    protected function target()
    {
        echo 'Boss -> target()';
    }
}

class Boy extends Boss
{
    public function target()
    {
        echo 'Boy -> target()';
    }
}

$boy = new Boy();
$boy -> target();
?>

执行效果

Child -> target()

注:

重写父类的方法只会影响到继承该类并重写了该方法的子类对象,其他继承该类的对象不会受到影响。

当子类重写父类的方法时,它实际上是在子类中创建了一个与父类方法具有相同 签名(函数的签名指的是函数的名称以及其参数列表的组合,它定义了函数的唯一标识符,用于区分不同的函数) 的新方法。这个新方法将覆盖(或取代)父类中的方法。当通过子类对象调用该方法时,将执行子类中的方法而不是父类中的方法。

其他继承了父类但没有重写该方法的子类对象仍然会继续使用父类中的方法,重写只会影响到具体进行重写操作的子类及其实例对象

将受保护成员重写为私有成员
<?php
class Boss
{
    protected function target()
    {
        echo 'Boss -> target()';
    }
}

class Boy extends Boss
{
    private function target()
    {
        echo 'Boy -> target()';
    }
}

$boy = new Boy();
$boy -> target();
?>

执行效果

在 PHP 中,当子类重写父类的方法时,重写的方法的访问修饰符不能比父类中的方法更严格。在上述代码中,父类的 target() 方法被定义为 protected 访问修饰符,而子类中重写的 target() 方法被定义为 private 访问修饰符,PHP 由此抛出了异常信息。

Fatal error: Access level to Boy::target() must be protected (as in class Boss) or weaker in C:\WWW\index.php on line 21
为什么不允许子类成员设置比父类成员更严格的访问限制?

在继承过程中,子类中的方法的访问修饰符不允许设置比父类更严格,主要是出于以下几个原因:

  1. 继承的一致性
    继承是一种行为,子类继承了父类的属性和方法,并且可以通过重写方法来改变其行为。如果子类中的方法访问修饰符设置得比父类更严格,那么就 破坏了继承的一致性,导致子类无法完全替代父类的功能

  2. 多态性的保证
    继承关系中的多态性是面向对象编程的重要特性之一。子类可以以父类的形式存在,而父类中的方法可以被子类重写。如果子类中的方法访问修饰符比父类更严格,那么 无法保证子类以父类的形式出现时,能够正确地调用和执行相应的方法

当一个方法在父类中被声明为公有(public),意味着该方法对外部是可见的,其他类可以自由地访问和使用它。如果子类中将该方法的访问修饰符设置为私有(private)或受保护(protected),则违反了父类对外提供的访问权限,导致无法在子类或其他类中正确地访问该方法。

继承关系中,子类应该是父类的扩展,它应该继承并保留父类的接口和行为。子类的方法的访问修饰符应该不严于父类,以确保子类能够正常地访问和重写父类的方法。这样可以保持代码的一致性,遵循面向对象编程的原则,提高代码的可读性、可维护性和可扩展性。

因此,在继承过程中,不允许子类中的方法的访问修饰符设置比父类更严格,以保证继承关系的正确性和代码的稳定性。

final 关键字

final 关键字在 PHP 中用于限制类、方法或属性的继承和重写。它的主要功能如下:

作用对象 功能和作用
防止其他类继承,保证实现的安全性和稳定性
方法 防止子类重写父类方法,保持方法行为的一致性和可预测性
属性 属性不能声明为 final,只有类和方法可以。属性的可见性可以通过访问修饰符来控制,但无法使用 final 限制属性的继承或修改。

使用 final 关键字可以在类的设计中提供一定的约束和保护机制。它能够防止意外的修改、继承或重写,从而增加代码的可维护性和可靠性。需要注意的是,final 关键字应该谨慎使用,只在必要的情况下才使用,以免过度限制类的扩展和修改。

当一个类被声明为 final,它将不能被其他类继承。这样可以确保该类的实现不会被修改或扩展,提供了一定的安全性和稳定性。

举个栗子

<?php
final class Boss
{
    function target()
    {
        echo 'Boss -> target()';
    }
}


class Boy extends Boss
{

}
?>

执行效果

Fatal error: Class Boy may not inherit from final class (Boss) in C:\WWW\index.php on line 14
方法

当一个方法被声明为 final,它将不能被子类重写。这样可以确保该方法的行为不会被修改,保持一致性和可预测性。子类无法改变父类中标记为 final 的方法的实现。

举个栗子

<?php
class Boss
{
    final protected function target()
    {
        echo 'Boss -> target()';
    }
}


class Boy extends Boss
{
    public function target()
    {
        echo 'Boy -> target';
    }
}
?>

执行效果

Fatal error: Cannot override final method Boss::target() in C:\WWW\index.php on line 17
属性

在 PHP 中,属性不能被声明为 final,只有类和方法可以。属性的可见性可以通过访问修饰符来控制,但无法使用 final 限制属性的继承或修改。

举个栗子

<?php
class Boss
{
    final protected $target = 'Boss -> $target';
}


class Boy extends Boss
{
    public $target = 'Boy -> $target';
}
?>

执行效果

Fatal error: Cannot declare property Boss::$target final, the final modifier is allowed only for methods and classes in C:\WWW\index.php on line 4
final 关键字为什么不允许用于属性?

在 PHP 中,final 关键字只能用于类和方法,不能用于属性。这是 因为属性是对象的状态,它的值可以在运行时发生变化,而 final 关键字的作用是为了限制类和方法的修改和继承,保持其一致性和稳定性。如果属性可以被声明为 final,那么子类将无法修改属性的值,这将 违反对象的状态可变的原则
另外,属性的可见性可以通过访问修饰符来控制,无需使用 final 关键字来限制属性的继承或修改。

类常量的可见性

类常量

在 PHP 中,类常量是在类定义中被定义的固定值,其值在定义时被设置,并在整个类的生命周期中保持不变。类常量适用于那些在类中具有全局性质,不需要修改的值。类常量可以直接通过类名来访问,而无需创建类的实例。

声明类常量

使用 const 关键字来声明类常量,通常位于类的顶部,在任何方法之外(类常量需要于顶层作用域中声明,否则,PHP 将抛出错误信息)。常量名称通常使用大写字母,并且可以使用下划线来分隔单词。

class MyClass {
    const CONSTANT_NAME = 'constant value';
}
访问类常量

可以使用类名和作用域解析操作符 :: 来访问类常量。常量的访问不需要使用 $ 符号。

echo MyClass::CONSTANT_NAME;
常量的可见性

可以使用访问修饰符(publicprotectedprivate)来指定常量的可见性。默认情况下,常量被视为公共成员(public)的,可以在任何地方访问。

class MyClass {
    public const PUBLIC_CONSTANT = 'public';
    protected const PROTECTED_CONSTANT = 'protected';
    private const PRIVATE_CONSTANT = 'private';
}
类常量的特性

类常量是类的属性,不属于类的实例。它们在类定义时被设置,并且在整个类的生命周期中保持不变。类常量的值可以是字符串、数值或布尔值等。

class Math {
    const PI = 3.14;
    const MAX_VALUE = 100;
}

类常量与访问修饰符

在 PHP 中,类常量可以使用访问修饰符(publicprotectedprivate)来指定它们的可见性,这与类属性和类方法的可见性控制方式是一样的。

使用访问修饰符来声明类常量的可见性是从 PHP 7.1.0 版本开始引入的。在此之前的版本,类常量都是公共(public)的,并且不能使用访问修饰符来指定其可见性。

举个栗子

<?php
class MyClass
{
    protected const SECRET = 'Secret';
    function spy()
    {
        # 在类的内部对类常量进行访问
        echo self::SECRET;
    }
}

class Boy extends MyClass
{
    function backdoor()
    {
        # 在 MyClass 的子类中访问位于父类的受保护成员
        echo MyClass::SECRET;
    }
}
# 由于 MyClass::SECRET 为 MyClass 类的受保护成员
# 因此,无法在类的外部直接访问,
# 取消 echo '【Outside】' . MyClass::SECRET;
# 代码的注释,PHP 将抛出异常错误信息。
//echo '【Outside】' . MyClass::SECRET;
//echo "\n";

# 通过调用实例方法 spy() 对类常量间接进行访问
$myClass = new MyClass();
$myClass -> spy();
echo "\n";

# 通过子类间接访问父类中的受保护成员
$visitor = new Boy();
$visitor -> backdoor();
?>

执行效果文章来源地址https://www.toymoban.com/news/detail-447841.html

Secret
Secret

到了这里,关于闪耀的钥匙:PHP 与访问修饰符的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java的访问修饰符

    为了实现面向对象程序设计(OOP)的封装这个特性,需要程序设计语言提供一定的语法机制来支持。这个语法机制就是访问权限控制(访问修饰符:public、protected、private、default)。 在 Java 中,封装就意味着所有的实例域都带有 private 访问修饰符(私有的实例域),并提供带

    2023年04月15日
    浏览(40)
  • Java 包、访问修饰符

    2024年02月13日
    浏览(36)
  • C++ 类访问修饰符

    数据封装是面向对象编程的一个重要特点,它防止函数直接访问类类型的内部成员。类成员的访问限制是通过在类主体内部对各个区域标记 public、private、protected 来指定的。 public、private、protected 称为访问修饰符。 一个类可以有多个 public、protected 或 private 标记区域。

    2024年02月02日
    浏览(36)
  • 6.php开发-个人博客项目&Tp框架&路由访问&安全写法&历史漏洞

    目录 知识点 php框架——TP URL访问 Index.php-放在控制器目录下 ​编辑 Test.php--要继承一下 带参数的—————— 加入数据库代码 --不过滤 --自己写过滤 --手册(官方)的过滤 用TP框架找漏洞: 如何判断网站是thinkphp? 黑盒: 白盒: php总结 ​ 1-基于TP框架入门安装搭建使用

    2024年01月25日
    浏览(54)
  • C++入门【35-类访问修饰符】

    数据封装是面向对象编程的一个重要特点,它防止函数直接访问类类型的内部成员。类成员的访问限制是通过在类主体内部对各个区域标记 public、private、protected 来指定的。 public、private、protected 称为访问修饰符。 一个类可以有多个 public、protected 或 private 标记区域

    2024年01月24日
    浏览(33)
  • C#的访问修饰符详解(二)

    在C#中,internal修饰符是一种访问修饰符,它用于控制类成员的访问范围。一个internal成员只能在其定义的程序集中访问,而不能在其他程序集中访问。本文将介绍internal修饰符的使用方法和实例。 internal修饰符的主要作用是控制数据的访问级别。通过将类的成员声明为interna

    2024年02月03日
    浏览(34)
  • 访问修饰符private,default,protected,public访问等级区别

    private : private 是最严格的访问修饰符,它将成员声明为私有的。私有成员只能在声明它们的类内部访问,其他类无法直接访问私有成员。这样可以确保数据的封装性和安全性。 default (默认):如果没有明确指定访问修饰符,成员将具有默认的访问修饰符。默认修饰符在同

    2024年02月08日
    浏览(41)
  • Java访问权限之 protected 修饰符

            在Java中,使用访问权限修饰符来保护对类、变量、方法和构造方法的访问,这类修饰符分别是public,protected,default,以及private。由于很多Java书籍对protected可见性的介绍都比较笼统,本文重点说明protected的权限 各访问修饰符权限如下: 同一个类中 同一个包内 不同

    2024年02月05日
    浏览(40)
  • 【Java|基础篇】包和访问权限修饰符

    包和访问权限修饰符是Java中两个常用的概念,它们都与访问控制有关. 在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。Java中的包(Package)是一种用于组织类、接口、枚举等Java元素的机制。它被设计用于解

    2024年02月05日
    浏览(47)
  • Java接口中方法的默认访问控制修饰符

    在Java接口中,如果方法的访问控制修饰符没有声明,隐含着是public的。这个public可加上,也可以不加上。但为简洁起见,建议不加。 示例: 下面代码定义了有接口,有两个函数,其中一个没有声明public的,另外一个明确声明了public的: 打开编译后的class文件,可以发现,即

    2024年02月15日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包