13 Php学习:面向对象

news2025/6/8 18:56:55

PHP 面向对象

面向对象(Object-Oriented,简称 OO)是一种编程思想和方法,它将程序中的数据和操作数据的方法封装在一起,形成"对象",并通过对象之间的交互和消息传递来完成程序的功能。面向对象编程强调数据的封装、继承、多态和动态绑定等特性,使得程序具有更好的可扩展性、可维护性和可重用性。
在这里插入图片描述

在面向对象的程序设计(英语:Object-oriented programming,缩写:OOP)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。

在现实世界里我们所面对的事情都是对象,如计算机、电视机、自行车等。

对象的主要三个特性:

  • 对象的行为:对象可以执行的操作,比如:开灯,关灯就是行为。
  • 对象的形态:对对象不同的行为是如何响应的,比如:颜色,尺寸,外型。
  • 对象的表示:对象的表示就相当于身份证,具体区分在相同的行为与状态下有什么不同。

面向对象编程的三个主要特性:

  • 封装(Encapsulation):指将对象的属性和方法封装在一起,使得外部无法直接访问和修改对象的内部状态。通过使用访问控制修饰符(public、private、protected)来限制属性和方法的访问权限,从而实现封装。

  • 继承(Inheritance):指可以创建一个新的类,该类继承了父类的属性和方法,并且可以添加自己的属性和方法。通过继承,可以避免重复编写相似的代码,并且可以实现代码的重用。

  • 多态(Polymorphism):指可以使用一个父类类型的变量来引用不同子类类型的对象,从而实现对不同对象的统一操作。多态可以使得代码更加灵活,具有更好的可扩展性和可维护性。在 PHP 中,多态可以通过实现接口(interface)和使用抽象类(abstract class)来实现。

面向对象内容

  • 类 − 定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。
    在这里插入图片描述

  • 对象 − 是类的实例。

  • 成员变量 − 定义在类内部的变量。该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可成为对象的属性。

  • 成员函数 − 定义在类的内部,可用于访问对象的数据。

  • 继承 − 继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。

  • 父类 − 一个类被其他类继承,可将该类称为父类,或基类,或超类。

  • 子类 − 一个类继承其他类称为子类,也可称为派生类。

  • 多态 − 多态性是指相同的函数或方法可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。

  • 重载 − 简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。

  • 抽象性 − 抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质,而忽略其他一些无关内容。任何类的划分都是主观的,但必须与具体的应用有关。

  • 封装 − 封装是指将现实世界中存在的某个客体的属性与行为绑定在一起,并放置在一个逻辑单元内。

  • 构造函数 − 主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

  • 析构函数 − 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做"清理善后" 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

PHP 类定义

<?php
class phpClass {
  var $var1;
  var $var2 = "constant string";
  
  function myfunc ($arg1, $arg2) {
     [..]
  }
  [..]
}
?>

  • 类使用 class 关键字后加上类名定义。

  • 类名后的一对大括号({})内可以定义变量和方法。

  • 类的变量使用 var 来声明, 变量也可以初始化值。

  • 函数定义类似 PHP 函数的定义,但函数只能通过该类及其实例化的对象访问。

<?php
class Site {
  /* 成员变量 */
  var $url;
  var $title;
  
  /* 成员函数 */
  function setUrl($par){
     $this->url = $par;
  }
  
  function getUrl(){
     echo $this->url . PHP_EOL;
  }
  
  function setTitle($par){
     $this->title = $par;
  }
  
  function getTitle(){
     echo $this->title . PHP_EOL;
  }
}
?>

PHP 中创建对象

类创建后,我们可以使用 new 运算符来实例化该类的对象:


$taobao = new Site;
$google = new Site;

调用成员方法

// 调用成员函数,设置标题和URL

$taobao->setTitle( "淘宝" );
$google->setTitle( "Google 搜索" );


$taobao->setUrl( 'www.taobao.com' );
$google->setUrl( 'www.google.com' );

// 调用成员函数,获取标题和URL

$taobao->getTitle();
$google->getTitle();

$taobao->getUrl();
$google->getUrl();

PHP 构造函数

构造函数是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与 new 运算符一起使用。

PHP 5 允许开发者在一个类中定义一个方法作为构造函数,语法格式如下:

void __construct ([ mixed $args [, $... ]] )

举例

function __construct( $par1, $par2 ) {
   $this->url = $par1;
   $this->title = $par2;
}

析构函数

析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。

PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,其语法格式如下:

void __destruct ( void )

举例

<?php
class MyDestructableClass {
   function __construct() {
       print "构造函数\n";
       $this->name = "MyDestructableClass";
   }

   function __destruct() {
       print "销毁 " . $this->name . "\n";
   }
}

$obj = new MyDestructableClass();
?>

继承

PHP 使用关键字 extends 来继承一个类,PHP 不支持多继承,格式如下:

class Child extends Parent {
   // 代码部分
}

实例

<?php 
// 子类扩展站点类别
class Child_Site extends Site {
   var $category;

    function setCate($par){
        $this->category = $par;
    }
  
    function getCate(){
        echo $this->category . PHP_EOL;
    }
}

方法重写

如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

实例中重写了 getUrl 与 getTitle 方法:

function getUrl() {
   echo $this->url . PHP_EOL;
   return $this->url;
}
   
function getTitle(){
   echo $this->title . PHP_EOL;
   return $this->title;
}

访问控制

PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。

  • public(公有):公有的类成员可以在任何地方被访问。
  • protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
  • private(私有):私有的类成员则只能被其定义所在的类访问。

属性的访问控制

类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有。

<?php
/**
 * Define MyClass
 */
class MyClass
{
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj = new MyClass();
echo $obj->public; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // 可以对 public 和 protected 进行重定义,但 private 而不能
    protected $protected = 'Protected2';

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj2 = new MyClass2();
echo $obj2->public; // 这行能被正常执行
echo $obj2->private; // 未定义 private
echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined

?>

方法的访问控制

类中的方法可以被定义为公有,私有或受保护。如果没有设置这些关键字,则该方法默认为公有。

<?php
/**
 * Define MyClass
 */
class MyClass
{
    // 声明一个公有的构造函数
    public function __construct() { }

    // 声明一个公有的方法
    public function MyPublic() { }

    // 声明一个受保护的方法
    protected function MyProtected() { }

    // 声明一个私有的方法
    private function MyPrivate() { }

    // 此方法为公有
    function Foo()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}

$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
$myclass->MyProtected(); // 这行会产生一个致命错误
$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // 公有,受保护,私有都可以执行


/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
    // 此方法为公有
    function Foo2()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate(); // 这行会产生一个致命错误
    }
}

$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行

class Bar 
{
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }

    public function testPublic() {
        echo "Bar::testPublic\n";
    }
    
    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}

class Foo extends Bar 
{
    public function testPublic() {
        echo "Foo::testPublic\n";
    }
    
    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}

$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate 
                // Foo::testPublic
?>

接口

使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。

接口中定义的所有方法都必须是公有,这是接口的特性。

要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

<?php

// 声明一个'iTemplate'接口
interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}


// 实现接口
class Template implements iTemplate
{
    private $vars = array();
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
  
    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }
 
        return $template;
    }
}

常量

可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号。

常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。

自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字(如 self,parent 或 static)

<?php
class MyClass
{
    const constant = '常量值';

    function showConstant() {
        echo  self::constant . PHP_EOL;
    }
}

echo MyClass::constant . PHP_EOL;

$classname = "MyClass";
echo $classname::constant . PHP_EOL; //5.3.0 起

$class = new MyClass();
$class->showConstant();

echo $class::constant . PHP_EOL; // 自 PHP 5.3.0 起
?>

抽象类

任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。

定义为抽象的类不能被实例化。

被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。

<?php
abstract class AbstractClass
{
 // 强制要求子类定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . PHP_EOL;
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') . PHP_EOL;

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') . PHP_EOL;
?>

此外,子类方法可以包含父类抽象方法中不存在的可选参数。

例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则也是可以正常运行的。

<?php
abstract class AbstractClass
{
    // 我们的抽象方法仅需要定义需要的参数
    abstract protected function prefixName($name);

}

class ConcreteClass extends AbstractClass
{

    // 我们的子类可以定义父类签名中不存在的可选参数
    public function prefixName($name, $separator = ".") {
        if ($name == "Pacman") {
            $prefix = "Mr";
        } elseif ($name == "Pacwoman") {
            $prefix = "Mrs";
        } else {
            $prefix = "";
        }
        return "{$prefix}{$separator} {$name}";
    }
}

$class = new ConcreteClass;
echo $class->prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>

Static 关键字

声明类属性或方法为 static(静态),就可以不实例化类而直接访问。

静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。

由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。

静态属性不可以由对象通过 -> 操作符来访问。

自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。

<?php
class Foo {
  public static $my_static = 'foo';
  
  public function staticValue() {
     return self::$my_static;
  }
}

print Foo::$my_static . PHP_EOL;
$foo = new Foo();

print $foo->staticValue() . PHP_EOL;
?>    

Final 关键字

PHP 5 新增了一个 final 关键字。如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。

<?php
class BaseClass {
   public function test() {
       echo "BaseClass::test() called" . PHP_EOL;
   }
   
   final public function moreTesting() {
       echo "BaseClass::moreTesting() called"  . PHP_EOL;
   }
}

class ChildClass extends BaseClass {
   public function moreTesting() {
       echo "ChildClass::moreTesting() called"  . PHP_EOL;
   }
}
// 报错信息 Fatal error: Cannot override final method BaseClass::moreTesting()
?>

调用父类构造方法

PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。

<?php
class BaseClass {
   function __construct() {
       print "BaseClass 类中构造方法" . PHP_EOL;
   }
}
class SubClass extends BaseClass {
   function __construct() {
       parent::__construct();  // 子类构造方法不能自动调用父类的构造方法
       print "SubClass 类中构造方法" . PHP_EOL;
   }
}
class OtherSubClass extends BaseClass {
    // 继承 BaseClass 的构造方法
}

// 调用 BaseClass 构造方法
$obj = new BaseClass();

// 调用 BaseClass、SubClass 构造方法
$obj = new SubClass();

// 调用 BaseClass 构造方法
$obj = new OtherSubClass();
?>

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1592591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

理想大模型实习面试题6道|含解析

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

在 Google Cloud 上轻松部署开放大语言模型

今天&#xff0c;“在 Google Cloud 上部署”功能正式上线&#xff01; 这是 Hugging Face Hub 上的一个新功能&#xff0c;让开发者可以轻松地将数千个基础模型使用 Vertex AI 或 Google Kubernetes Engine (GKE) 部署到 Google Cloud。 Model Garden (模型库) 是 Google Clou…

Qt | 视频播放器(multimedia、multimediawidgets)

QT +=multimedia 通俗解释: 此代码行告诉编译器在构建应用程序时包含多媒体库。这意味着您的应用程序将能够播放和显示音频和视频文件。 使用分步说明构建模型: 创建一个新的 Qt 项目。 在 .pro 文件中添加以下行: QT += multimedia 导入必要的多媒体头文件: #include &l…

Android 加密之 打包为arr 项目依赖或者为jar

Android 加密之 打包为arr 项目依赖或者为jar 1. 修改build.gradle plugins {//id com.android.application// 1. 修改为libraryid com.android.library }android {namespace com.dzq.iccid2compileSdk 33defaultConfig {//applicationId "com.dzq.iccid2"// 2. 注…

嵌入式驱动学习第七周——I2C子系统

前言 I2C子系统详解&#xff0c;本篇博客从内核源码的角度来看I2C子系统。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xff0c;一起讨论一起学习。现在关注就是老粉啦…

爱奇艺APP Android低端机性能优化

01 背景介绍 在智能手机市场上&#xff0c;高端机型经常备受瞩目&#xff0c;但低端机型亦占据了不可忽视的份额。众多厂商为满足低端市场的需求&#xff0c;不断推出低配系列手机。另外过去几年的中高端机型&#xff0c;随着系统硬件的快速迭代&#xff0c;现已经被归类为低端…

学习Rust的第4天:常见编程概念

欢迎来到学习Rust的第四天&#xff0c;基于Steve Klabnik的《The Rust Programming Language》一书。昨天我们做了一个 猜谜游戏 &#xff0c;今天我们将探讨常见的编程概念&#xff0c;例如&#xff1a; Variables 变量Constants 常数Shadowing 阴影Data Types 数据类型Functi…

错题记录(2)

来源&#xff1a; FPGA开发/数字IC笔试系列(10) 笔试刷题 笔试 | 海思2022数字IC模拟卷&#xff08;真题模拟&#xff0c;带解析&#xff09; 运算符优先级

【C++算法竞赛 · 图论】图的存储

前言 图的存储 邻接矩阵 方法 复杂度 应用 例题 题解 邻接表 方法 复杂度 应用 前言 上一篇文章中&#xff08;【C算法竞赛 图论】图论基础&#xff09;&#xff0c;介绍了图论相关的概念和一种图的存储的方法&#xff0c;这篇文章将会介绍剩下的两种方法&#xff…

【黑马头条】-day09用户行为-精度丢失-点赞收藏关注

文章目录 1 long类型精度丢失问题1.1 解决1.2 导入jackson序列化工具1.3 自定义注解1.4 原理1.5 测试 2 用户行为要求3 创建微服务behavior3.1 微服务创建3.2 添加启动类3.3 创建bootstrap.yml3.4 在nacos中配置redis3.5 引入redis依赖3.6 更新minio 4 跳过 1 long类型精度丢失…

视频批量高效剪辑,支持将视频文件转换为音频文件,轻松掌握视频格式

在数字化时代&#xff0c;视频内容日益丰富&#xff0c;管理和编辑这些视频变得愈发重要。然而&#xff0c;传统的视频剪辑软件往往操作复杂&#xff0c;难以满足高效批量处理的需求。现在&#xff0c;一款全新的视频批量剪辑神器应运而生&#xff0c;它支持将视频文件一键转换…

【vue】slot 匿名插槽 / 具名插槽

slot父组件向子组件传递数据 匿名插槽–直接写 具名插槽–指定名称 父组件中 子组件中&#xff1a; 代码 App.vue <template><h2>App.vue</h2><!-- 匿名插槽 --><Header><a href"1234567890.com">1234567890</a>&…

Bug的定义生命周期

1、bug的定义 你们觉得bug是什么? 软件的Bug狭义概含是指软件程序的漏洞或缺陷&#xff0c; 广义概念除此之外还包括测试工程师或用户所发现和提出的软件可改进的细节(增强性&#xff0c;建议性)、或 与需求文档存在差异的功能实现等。 我们的职责就是&#xff0c;发现这些B…

002nodejs详细安装步骤和npm配置

1、Node.js简介 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时。Node.js 使用高效、轻量级的事件驱动、非阻塞 I/O 模型。它的包生态系统&#xff0c;npm&#xff0c;是目前世界上最大的开源库生态系统。 2、下载Node.js 官方地址&#xff1a;https://nodejs.org/…

vue3 知识点的补充 之 第一节

01 vue2与vue3的区别 vue2 采用object.defuneProperty()实现 对数组不友好 重写了数组的方法&#xff0c;同时无法监听数组length长度的改变。对于对象只能劫持设置好的数据 新增需要使用vue.set vue3 采用proxy进行代理&#xff0c;不需要重写数组的方法 同时可以监听数组长度…

plsql developer 一键格式化sql/美化sql

PL/SQL 格式化工具 以 Oracle SQL Developer 为例&#xff0c;使用一键格式化的步骤如下&#xff1a; 打开 Oracle SQL Developer。在“文件”菜单中&#xff0c;选择“打开文件”&#xff0c;然后选择你的 PL/SQL 文件。打开文件后&#xff0c;你可以通过右键菜单选择“格式…

机器学习——自动驾驶

本章我们主要学习以下内容: 阅读自动驾驶论文采集数据根据论文搭建自动驾驶神经网络训练模型在仿真环境中进行自动驾驶 论文介绍 本文参考自2016年英伟达发表的论文《End to End Learning for Self-Driving Cars》 📎end2end.pdf

全栈的自我修养 ———— 如何发布一个npm包?

创建本地仓库 npm init在此期间会让你添加一些版本信息和名称 登陆npm npm login ——> yinhaodada arx.040208发布 npm publish查询

微服务(基础篇-008-Elasticsearch分布式搜索【上】)

目录 初识elasticsearch&#xff08;1&#xff09; 了解ES&#xff08;1.1&#xff09; 倒排索引&#xff08;1.2&#xff09; es的一些概念&#xff08;1.3&#xff09; 安装es、kibana&#xff08;1.4&#xff09; ik分词器&#xff08;1.5&#xff09; ik分词器的拓展…

RT-Thread内核简介

1、RT-Thread 内核介绍 RT-Thread 内核架构图,内核处于硬件层之上,内 核部分包括内核库、实时内核实现 内核库是为了保证内核能够独立运行的一套小型的类似 C 库的函数实现子集。这部分根据编译器的不 同自带 C 库的情况也会有些不同,当使用 GNU GCC 编译器时,会携带…