PHP面向对象编程(一)

PHP类与对象、访问控制

概述

面向对象编程(OOP)是一种计算机编程架构,和基于函数构建程序不同,面向对象编程的思想是在程序中包含各种独立而又相互调用的对象,每一个对象都能够接受数据、处理数据(对象方法实现)、并将数据表达给其他对象,当我们下达指令时,不再是调用函数,而是指定对象的方法。因此,在面向对象编程中,对象是程序的基本单元,一个对象包含了数据和操作数据的函数。

面向对象的中最核心的概念就是类(Class)和对象(Object),类是对象的抽象模板,而对象是类的具体实例。

编写自定义类

以汽车为例编写一个自定义类Car

<?php
class Car
{

}

类通过关键字class进行声明,然后紧跟类名Car(通常以大写字母开头定义类名)

//通过php内置class_exists方法判断该类是否存在
if (class_exists('Car')) {
    echo 'Car存在';
}else{
    echo 'Car不存在';
}

类属性

类属性可以是变量,也可以是常量。

<?php

class Car
{
    const WHEELS = 4; //汽车都是4个轮子
    var $seats; //座位
    var $doors; //门
    var $engine; //发动机
    var $brand; //品牌
}

通过var来定义变量属性,通过const来定义常量属性(常量大写无$前缀)

类方法

<?php

class Car
{
    const WHEELS = 4; //汽车都是4个轮子
    var $seats; //座位
    var $doors; //门
    var $engine; //发动机
    var $brand; //品牌

    /**
     * @return mixed
     */
    public function getBrand()
    {
        return $this->brand;
    }

    /**
     * @param mixed $brand
     */
    public function setBrand($brand)
    {
        $this->brand = $brand;
    }

    /**
     * 开车
     */
    public function drive()
    {
        echo "1.启动引擎..." . PHP_EOL;
        echo "2.挂D档..." . PHP_EOL;
        echo "3.放下手刹..." . PHP_EOL;
        echo "4.踩油门,出发..." . PHP_EOL;
    }

    /**
     * 熄火
     */
    public function close()
    {
        echo "1.踩刹车..." . PHP_EOL;
        echo "2.挂P档..." . PHP_EOL;
        echo "3.拉起手刹..." . PHP_EOL;
        echo "4.关闭引擎..." . PHP_EOL;
    }

}

实例化对象

通过new关键字进行类的实例化

$car = new Car();

类常量是类级别的,无需实例化即可访问,类常量不能更改只能访问,在类外面访问常量,需要通过类名+::+常量名称的方式:

var_dump(Car::WHEELS);

对象级别的类属性(变量类型),需要实例化对象才能访问。

//修改类属性
$car->seats = 5;
//访问类属性
var_dump($car->seats);

访问类方法 通过对象实例+->+对象名即可

$car->drive();

构造函数

上述对象实例化是通过new Car()来实现的,这段代码实际上调用了Car的缺省构造函数,构造函数的用途是在对象实例化过程中调用,用于对对象的一些初始化操作。

/**
     * Car constructor.
     * @param $seats
     * @param $doors
     * @param $engine
     * @param $brand
     */
    public function __construct($seats, $doors, $engine, $brand)
    {
        $this->seats = $seats;
        $this->doors = $doors;
        $this->engine = $engine;
        $this->brand = $brand;
    }

访问控制

PHP通过public(公开)、protected(保护)、private(私有)关键字控制类属性和方法的可见性:

  • 对于通过public声明的属性和方法,在类以外和继承类中均可见;
  • 对于通过protected声明的属性和方法,在继承类(支持多层级)中可见,类以外不可见;
  • 对于private声明的属性和方法,仅在当前类内部可见,在继承类和类以外不可见

所谓的「可见」与「不可见」,是一种形象的说法,实际含义是可访问可设置。我们前面定义的类方法都是通过 PhpStorm 自带模版生成的,默认都是 public 声明,对于构造函数来说,除了单例模式这种特殊场景,其他都是需要通过 public 声明,否则在类以外不可见影响对象实例化。对于操作属性的 Getters/Setters 方法通常用于从外部处理 private 类型属性,所以也需要声明为 public,其他的场景可以根据具体业务场景需求来。

我们之前通过 var 声明类属性,这是比较老的用法,是为了向后兼容 PHP 4,在 PHP 5 中,通过 var 声明的属性和方法统统被视作 public,所以我们在测试代码中可以从外部直接访问和设置,下面,我们将其都设置为 protected 类型,以便在当前类和继承类中可见,在类以外不可见,从而保护对应属性不被恶意修改:

protected $seats;         // 座位
protected $doors;         // 门
protected $engine;        // 发动机
protected $brand;         // 品牌

面向对象三个特性 :继承、封装、多态

继承

PHP遵循单继承机制,即一个子类只能继承一个父类。

所谓继承,指的是子类可以通过继承的方式访问父类的属性和方法(protected或者public方式定义),在php中,集成通过extends关键字实现。

class Benz extends Car
{
    public function __construct($seats=5, $doors=4, $engine=1)
    {
        $this->brand = '奔驰';
        parent::__construct($seats, $doors, $engine, $this->brand);
    }
}

extends Car的含义就是Benz继承自Car,是他的子类,相对的,Car是Benz父类。

子类调用父类的同名方法需要通过parent::进行调用。

封装

概念

封装一方面指的是调用者无需关心对象实现细节,另一方面是通过访问控制限定属性和方法的可见性。

反射

可以通过反射的方式调用类的私有方法。

class Benz extends Car
{
    private $customProp = '自定义属性';
    public function __construct($seats=5, $doors=4, $engine=1)
    {
        $this->brand = '奔驰';
        parent::__construct($seats, $doors, $engine, $this->brand);
    }

    private function customMethod()
    {
        echo "Call custom prop \$customProp: " . $this->customProp . PHP_EOL;
    }

}


//通过反射调用私有方法
$method = new ReflectionMethod(Benz::class,'customMethod');
设置方法是否可执行
$method->setAccessible(true);

$benz = new Benz();
//执行一个反射方法
$method->invoke($benz);

多态

方法重写

所谓多态,指的是PHP继承体系中,子类可以重写父类同名方法。

类型转化

当类作为参数类型声明时,如果声明类型为父类,则可以传入子类对象,反过来,如果声明类型为子类,则不能传入父类对象。

PHP抽象类与接口

抽象类

抽象类指的是包含抽象方法的类,而抽象方法是通过abstract关键词修饰的方法,抽象方法只是一个方法,不能有具体实现:

abstract public function drive();

只要是某个类包含了至少一个抽象方法,他就是抽象类,抽象类也需要通过abstract关键词修饰。

<?php
abstract class Car
{
    abstract public function drive();
}

抽象类本身不能被实例化,只能被子类继承,继承了抽象类的子类必须实现父类的抽象方法。

接口

接口通过interface关键字声明,接口中可以定义多个方法声明,这些方法声明不能有任何实现,并且这些方法的可见性都应该是public,因为接口中的方法都要被其他类实现。

<?php
interface Car
{
	public function drive();
}

标识一个类实现了某个接口通过关键字implements完成。

<?php

interface Car
{
    public function drive();
}

class LynkCo01 implements Car
{
    protected $brand;

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

    public function drive()
    {
        echo "启动{$this->brand}汽车" . PHP_EOL;
    }
}

类型运算符 instanceof

instanceof,用于判断某个对象实例是否实现了某个接口,或者是某个父类/抽象类的子类实例

posted @ 2020-07-19 15:23  _大可乐  阅读(292)  评论(0编辑  收藏  举报