浅谈 PHP 面向对象基础 简单总结

本文深入探讨了面向对象编程的核心概念,包括继承、封装和多态性,详细讲解了类与对象的关系,以及如何使用PHP语言实现这些特性。文章还介绍了抽象类、接口、多态的实现方式,并讨论了关键字如final、clone、__set和__get等在面向对象编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象的三个特点:继承、封装和多态

类 是对 对象 的 抽象,在 类中 可以定义 对象的 属性和方法 的描述;

对象 是 类 的实例,类 只有被实例化后才能被使用。


instanceof  (1)判断一个对象是否是某个类的实例,(2)判断一个对象是否实现了某个接口。

// 用于检测当前对象属于哪个类
$obj = new A();
if ($obj instanceof A) {
   echo 'A';
}

一般在调用类的属性和方法的时候会使用:$this->name 或 $this->name()来完成。下面通过一个简单的例子来说明一下$this->$name的这种用法。

class Test{
    public $name = "abc";
    public $abc = "test";
    public function Test(){
        $name1 = "name";
        echo $this->name;   // 输出 abc
        echo $this->$name1;  // 输出 abc,因为 $name1 的值是name,相当与这里替换成 echo $this->name;
        $name2 = $this->$name1;  // $name2 的值是 abc
        echo $this->$name2;  // 输出 test,同上,相当与是 echo $this->abc;
    }
}
new Test();

构造方法 __construct 和 析构函数 __destruct(如果类名和方法名相同,则会当做构造函数来执行)

class BaseClass {
   function __construct() {
       echo "In BaseClass constructor";
   }
}
class SubClass extends BaseClass {
   function __construct() {
       parent::__construct();                // 要执行父类的析构函数,必须在子类的析构函数体中显式调用parent::__construct()
       echo "In SubClass constructor";       // 如果不引用父类的析构函数的话,则会自动调用本类的析构函数。
   }
}
class OtherSubClass extends BaseClass {
    // inherits BaseClass's constructor      // 子类如果自己没有定义析构函数,则会继承父类的。
}
$obj = new BaseClass();                      // In BaseClass constructor
$obj = new SubClass();                       // In BaseClass constructor   // In SubClass constructor
$obj = new OtherSubClass();                  // In BaseClass constructor

成员常量 (不会改变的量,是一个恒值)

class ClassName{
    const PI = 3.14159;
    public function aaa(){
        echo self::PI; //          类内推荐使用这种方法调用类成员属性
    }
}
echo ClassName::PI;  //3.14159     类外直接调用常量
$a = new ClassName();
$a->aaa();           //3.14159

私有成员 private 将数据完全隐藏起来,只能在类中被访问,类外与子类不能访问。

保护成员 protected 可以在本类和子类中被访问,其他地方则不能被调用。

class ClassName{
    protected $carName = '奥迪';
}
class car extends ClassName{
    public function say(){
        echo '父类:'.$this->carName; //$this只能在类的内部使用,"::"可以在没有声明任何实例的情况下访问类中的成员 (如下)
    }
}
$a = new car();
$a->say();           // 父类:奥迪
$b = new ClassName();
$b->carName          // 会报错 因为在类外部是无法访问protected修饰的常量,得写一个方法,要用public修饰。

  • “::”操作符

关键字::变量名/常量名/方法名

parent::关键字:可以调用父类中的公共的成员变量、公共的成员方法和公共的常量。

self::关键字:可以调用当前类中的静态成员和静态常量。

类名::关键字:可以调用本类中的公共的变量、公共的常量和公共的方法。

class ClassName{
    const PI = 3.14159;
    public function aaa(){
        return self::PI;
    }
    public function bbb(){
        return ClassName::aaa();
    }
    public function ccc(){
        return $this->carName;
    }
    protected $carName = '奥迪';
    private $carNames = '宝马';
}
class car extends ClassName{
    public function say(){
        echo '父类:'.parent::ccc();
        echo '父类:'.parent::bbb();
    }
}
$a = new car();
echo $a->say();            // 父类:奥迪父类:3.14159
echo $a->bbb();            // 3.14159
echo $a->carName;          // 会报错 因为在类外部是无法访问protected修饰的常量,得写一个方法,要用public修饰。

  • static关键字

  1. 关键字static修饰的成员属性称为 静态属性,成员方法称为 静态方法,它属于类本身而不属于类的任何实例。相当于存在类中的全局变量,可以在任何位置通过类名访问。如下:Web::change()

  2. “::”称为范围解析操作符,用于访问静态成员、静态方法和常量,还可以用于覆盖类中的成员和方法。

  3. 如果要在类内部的成员方法中的访问 静态属性 或者 要在类内部的成员方法中引用 静态方法 ,则只需要“self::静态属性/静态方法”即可。如下:self::$num,self::change()

class Web{
    static $num = 1;
    static function change(){
        echo "第".self::$num."位访客。";
        self::$num++;
    }
    public function fun(){
        echo self::change().'fun.';
    }
    public function webfun(){
        return self::$num.'&'.Web::$num;
    }
}
$web = new Web();
$web->change();                         // 第1位访客。
$web->change();                         // 第2位访客。
Web::change();                          // 第3位访客。fun.
Web::change();                          // 第4位访客。
echo Web::$num."\n";                    // 第5位访客。6
echo $web->webfun();                    // 6&6

  • 抽象类和接口

抽象类(abstract)和接口(Interface)都不能被实例化的特殊类。注:它们都是配合面向对象的多态性一起使用的。

  • 抽象类:
  1. 抽象类 是不能被实例化的类,只能作为其它类的父类使用。使用abstract关键字来声明。
  2. 抽象类 要只要包含一个抽象方法,且抽象方法中没有方法体,必须要在子类中来调用完成。注:抽象方法也是用abstract来修饰,且后面跟“;”号。
  3. 当子类继承抽象类以后,子类必须把父类中的抽象方法全部都实现,否则子类中还存在抽象方法,所以还是抽象类,也不能实例化对象。
  4. 抽象类:
abstract class Person{
    protected $name;
    protected $country;
    public function __construct($name="",$country="china"){
        $this->name = $name;
        $this->country = $country;
    }
    abstract function say();
    abstract function eat();
}
Class ChineseMan extends Person{
    public function say(){
        echo $this->name."是".$this->country."人";
    }
    public function eat(){
        echo $this->name."使用筷子吃饭";
    }
}
$chinaeseMan = new ChineseMan("知青");  // ChineseMan类中少Person类中两个抽象方法任何一个都会报错,必须全部实现,才能new
$chinaeseMan->say();  // 知青是china人
$chinaeseMan->eat();  // 使用筷子吃饭
  • 接口:
  1. PHP只支持单继承,如果想要多继承,就要使用接口,PHP可以实现多个接口。
  2. 接口中声明的方法必须是抽象方法,接口中不能声明变量,只能使用const关键字声明为常量的成员属性,且接口中的所有成员都必须具备public的访问权限,所以public 、abstract 可不写。
  3. 接口中 成员只能是常量 成员方法只能是抽象方法,且在子类必须把父类中抽象方法全部实现,否则子类中还存在接口,就不能实例化对象。
  4. 抽象类:
interface Person1{
    const SITENAME = '我在学习PHP';
    function show();
    function code();
}
interface Person2{      // 多个接口继承可使用extends 如: interface Person2 extends Person1
    function hello();
}
class Worker implements Person1,Person2{   // 继承接口使用implements关键字,多个接口用","拼接
    public function show(){
        return self::SITENAME;
    }
    public function code(){
        return '我在写代码';
    }
    public function hello(){
        return 'PHP是非常好的一种语言';
    }
}
$worker = new Worker();  // Worker类中少Person1或者Person2两个接口中任何一个方法都会报错,必须全部实现,才能new实例化对象
echo $worker->show();  // 我在学习PHP
echo $worker->code();  // 我在写代码
echo $worker->hello();  // PHP是非常好的一种语言
echo Person1::SITENAME; // 我在学习PHP

面向对象的多态

不同的对象,收到同一消息将可以产生不同的结果,这种现象称为多态性。

多态性的一般定义为:同一个操作作用于不同的类的实例,将产生不同的执行结果。即不同类的对象收到相同的消息时,将得到不同的结果。

多态即多种表现方式:,也作一个对外接口,多个内部实现方法。

实现多态有两种实现方法:

通过继承实现多态

abstract class parent1{
    abstract function travel();
}
// 通过继承实现多态
class car extends parent1{
    public function travel(){
        echo "开着小车去旅游";
    }
}
class bus extends parent1{
    public function travel(){
        echo "坐着大巴去旅游";
    }
}
function check($obj){
    if($obj instanceof car){
        $obj->travel();
    }elseif($obj instanceof bus){
        $obj->travel();
    }else{
        echo "Error: 对象错误!";
    }
}
check(new car()); // 开着小车去旅游
check(new bus()); // 坐着大巴去旅游

通过接口实现多态  

interface parent2{
    function travel();
}
class cars implements parent2{
    public function travel(){
        echo "开着小车去旅游";
    }
}
class buss implements parent2{
    public function travel(){
        echo "坐着大巴去旅游";
    }
}
function checkInterface($obj){
    if($obj instanceof cars){
        $obj->travel();
    }elseif($obj instanceof buss){
        $obj->travel();
    }else{
        echo "Error: 对象错误!";
    }
}
checkInterface(new cars()); // 开着小车去旅游
checkInterface(new buss()); // 坐着大巴去旅游

面向对象的其他关键字

  • final关键字 (最终的、最后的)

两种格式:

class parent1{
    final function travel(){
        echo '该方法在子类中不可被重写,也不可在被覆盖';
    }
}
final class parent1{
    // 该类不能再被继承,也不能在有子类
}

  • clone关键字 (克隆对象)

使用clone克隆的对象与原对象没有任何关系,它是将原对象从当前位置重新复制了一份,也就是相当于在内存中新开辟了一块空间。

对象克隆成功后,它们中的成员方法、属性以及值是完全相同的。如果要为克隆后的副本对象在克隆时候重新为成员赋初始值,就要使用魔术方法 __clone

 

class book{
    public function __construct($param){
        $this->param = $param;
    }
    public function type(){
        return $this->param;
    }
    public function __clone(){
        return $this->param = '克隆';
    }
}
$book1 = new book('原本');
echo $book1->type();         // 原本
$book2 = clone $book1;
echo $book2->type();         // 克隆

  • __set() 和 __get()方法

__set() 和 __get()方法 用于对私有成员进行 赋值 或者 获取值 的操作。

__set() 为私有的成员属性设置值,它不需要任何返回值。

__get() 在对象的外部获取私有成员属性的值,它返回一个允许对象在外部使用的值。

class Person{
    private $name;
    private $sex;
    private $age;
    public function __get($property_name){
        echo "在直接获取私有属性值的时候,自动调用了这个__get()方法";
        return $this->$property_name;
    }
    public function __set($property_name, $value){
        echo "在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值";
        $this->$property_name = $value;
    }
}
$p1 = new Person();
$p1->name = "张三";           // 在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
$p1->age = 20;                // 在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
echo "姓名:".$p1->name;      // 在直接获取私有属性值的时候,自动调用了这个__get()方法 姓名:张三
echo "性别:".$p1->sex;       // 在直接获取私有属性值的时候,自动调用了这个__get()方法 性别:
echo "年龄:".$p1->age;       // 在直接获取私有属性值的时候,自动调用了这个__get()方法 年龄:20

  • __isset() 和 __unset()方法

__isset()  可以对共有的成员属性进行检测,对于私有的成员属性无法检测。

如果类中存在 ”__isset()“方法,当在类外使用isset()函数检测对象中的私有成员属性时,就会自动调用“__isset()”方法完成对私有成员属性的检测。

在面向对象中,通过”unset()”函数可以对共有的成员进行 删除 操作,但是对于私有的成员属性,就必须有“__unset()”方法才能完成删除。

class Person {
    private $name;
    private $sex;
    private $age;
    public function __get($property_name) {
        if(isset($this->$property_name)){
            return $this->$property_name;
        }else{
            return '该参数不存在';
        }
    }
    public function __set($property_name, $value) {
        $this->$property_name = $value;
    }
    public  function __isset($nm) {
        echo "isset()函数测定私有成员时,自动调用";
        return isset($this->$nm);
    }
    public  function __unset($nm) {
        echo "当在类外部使用unset()函数来删除私有成员时自动调用的";
        unset($this->$nm);
    }
}
$p1 = new Person();
$p1->name = "this is a person name";          
var_dump(isset($p1->name));                 // isset()函数测定私有成员时,自动调用   bool(true)
echo $p1->name;                             // this is a person name
unset($p1->name);                           // 当在类外部使用unset()函数来删除私有成员时自动调用的
echo $p1->name;                             // isset()函数测定私有成员时,自动调用   该参数不存在

  • __call()方法

当程序试图调用不存在或不可见的成员方法时,PHP会先调用__call()方法来存储方法名及其参数。其中,方法参数是以数组形式来存在的。

class Fir {
    public function exist(){
        echo '调用方法存在';
    }
    public function __call($funName, $param) {
        echo '当方法不存在时候会自动调用此方法';
        echo '不存在的方法名为'.$funName;
        var_dump($param);
    }
}
$p1 = new Fir();
$p1->exist();                                // 调用方法存在
$p1->noexist('noExist','this is name');       // 当方法不存在时候会自动调用此方法 不存在的方法名为noexist array(2) { [0]=> string(7) "noExist" [1]=> string(12) "this is name" }

  • __toString()方法

作用:当使用echo 或print输出对象时,将对象转化为字符串。另外,__toString()需要return一个返回值。

输出对象时,应该注意echo或print函数后要直接跟要输出的对象,中间不要加多余的字符。否则__toString()方法不会被执行。

class Fir {
    public function __toString(){
        return '直接打印 new对象的时候 自动调用执行';
    }
}
$p1 = new Fir();
echo $p1;                // 直接打印 new对象的时候 自动调用执行

  • __autoload()方法

在指定路径下自动查找和该类名称相同的文件,如果找到,继续执行,否则报错。 

<?php
//  文件名为Fir.php
class Fir {
    public function __toString(){
        return '直接打印 new对象的时候 自动调用执行';
    }
}
function __autoload($className){            // 当new的类不存在时候 自动调用 __autoload()函数 并且 把new的类名作为参数传进去
    $classPath = $className.'.php';
    if (file_exists($classPath)) {
        include_once($classPath);           // $className = 'Fir'  相当于引入 Fir.php文件
    }else{
        echo '类路径错误';
    }
}
echo new Fir();                             // 当直接打印对象的时候 则调用自动__toString()函数 输出结果   直接打印 new对象的时候 自动调用执行。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值