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,用于判断某个对象实例是否实现了某个接口,或者是某个父类/抽象类的子类实例