前言
PHP中类具有封装、继承以及多态性,封装意思是我们可以将我们经常用的方法封装起来已达到复用以及尽量避免代码冗余的出现,继承则是我们可以去继承一个常态化的类以达到将其开放出来的方法复用以及改写的目的,多态意思就是各种编译时的状态不同,意思便是开放对外的接口只要一个,但是内部方法众多,指向性也不同,不同的输入可能会输出不同的内容,这就是多态的核心。
关于类与对象以及面向对象开发的理论知识,我就不作过多介绍了,大家有兴趣的可以去查阅相关资料自行了解。
类的定义
每个类的定义都以关键字 class 开头,后面跟着类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。
类名可以是任何非 PHP 保留字 的合法标签。一个合法类名以字母或下划线开头,后面跟着若干字母,数字或下划线。
一个类可以包含有属于自己的 常量,变量(称为“属性”)以及函数(称为“方法”)。
例:
<?php
class Student {
// 声明属性 姓名和学号public string $name;
public int $stuNo;
// 构造方法,对象实例化时调用public function __construct(string $name, int $stuNo) {
$this->name = $name;
$this->stuNo = $stuNo;
}
// 声明方法public function goToSchool() : void {
echo "姓名:".$this->name.",学号:".$this->stuNo;
}
}
// 对象实例化,使用new关键字
$liHua = new Student("李华",1001);
// 实例化后的对象调用了Student类中的方法
$liHua->goToSchool();
echo "\n";
// instanceof检测当前实例化对象是否属于Student类
var_dump($liHua instanceof Student);
运行结果:
当一个方法在类定义内部被调用时,有一个可用的伪变量 $this。$this 是一个到当前对象的引用。
要创建一个类的实例,必须使用 new 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了 构造函数 并且在出错时抛出了一个 异常。类应在被实例化之前定义(某些情况下则必须这样)。
如果在 new 之后跟着的是一个包含有类名的字符串 string,则该类的一个实例被创建。如果该类属于一个命名空间,则必须使用其完整名称。
例:
<?php
// 对象实例化
// 通过字符串方式
$student = "student";
$meiMei = new $student("美美",1002);
// 实例化后的对象调用了Student类中的方法
$meiMei->goToSchool();
echo "\n";
// instanceof检测当前实例化对象是否属于Student类
var_dump($meiMei instanceof Student);
运行结果:
PHP 8.0.0 起,支持任意表达式中使用 new。如果表达式生成一个 string,这将允许更复杂的实例化。表达式必须使用括号括起来。
例:
<?php
// 通过表达式方式对象实例化
(new Student("菜菜",1003))->goToSchool();
运行结果:
如果被实例化的类没有构造方法或者构造方法不需要传参的话,我们还可以用下面的方式来实例化一个对象。
例:
<?php
class Student {
// 声明属性 姓名和学号public string $name;
public int $stuNo;
// 构造方法,对象实例化时调用public function __construct() {}
// 声明方法public function goToSchool() : void {
echo "姓名:".$this->name.",学号:".$this->stuNo;
}
/**
* @param string $name
*/public function setName(string $name): void{
$this->name = $name;
}
/**
* @param int $stuNo
*/public function setStuNo(int $stuNo): void{
$this->stuNo = $stuNo;
}
}
// 对象实例化
// string方式
$huiHui = new("Student");
$huiHui->setName("辉辉");
$huiHui->setStuNo(1004);
$huiHui->goToSchool();
echo "\n";
// ::class常量方式
$pdd = new(Student::class);
$pdd->setName("pdd");
$pdd->setStuNo(1005);
$pdd->goToSchool();
运行结果:
属性和方法
通过前面我们定义的学生类,大家也应该注意到啦。一个完整的PHP类应该有属性、方法以及构造方法。通过我们的需求不同来声明定义不同的属性和方法,也可以在声明时限定属性以及方法的传参类型,在方法中包括传参和返参。
在类中,属性又叫字段,它代表了类所具有的基本属性,如学生类Student中的姓名name,学号stuNo。而方法则代表类所具有的行为功能,如goToSchool()方法,setName()方法,getName()方法等。
由于类型声明是在PHP7.4以后才出的新特性。所以,在大多数时候,我们实际开发中基本不做类型声明。如果我们使用的PHP版本是最新的PHP8版本的话,我建议大家可以在项目开发中多做类型声明,这样可以减少我们项目的出错率以及规范代码。
属性和方法的访问是通过对象操作符(->)来完成的,结合$this变量,我们就可以完成对属性和方法的相关操作。
类型属性必须在访问前初始化,否则会抛出 Error 。
例:
<?php
class Student {
// 声明属性 姓名和学号public string $name;
public int $stuNo;
// 构造方法,对象实例化时调用public function __construct() {}
// 声明方法public function goToSchool() : void {
echo "姓名:".$this->name.",学号:".$this->stuNo;
}
/**
* @param string $name
*/public function setName(string $name): void{
$this->name = $name;
}
/**
* @param int $stuNo
*/public function setStuNo(int $stuNo): void{
$this->stuNo = $stuNo;
}
/**
* @return string
*/public function getName(): string{
return $this->name;
}
/**
* @return int
*/public function getStuNo(): int{
return $this->stuNo;
}
}
// 对象实例化
$caiCai = new Student();
// 初始化属性
$caiCai->setName('菜菜');
$caiCai->setStuNo(1003);
// 访问已经初始化的属性
echo $caiCai->getName()."\n";
echo $caiCai->stuNo."\n";
//对象实例化
$san = new Student();
// 访问未初始化的属性
echo $san->getName()."\n";
echo $san->stuNo."\n";
运行结果:
注意:如果有认真看示例代码,我们会发现在访问属性stuNo时,我们并没有像访问name那样通过方法来访问。这就是由于访问控制所致,如果大家有过了解Java,那就会很容易理解,在访问控制上PHP与Java基本是一致的。
readonly类型声明
这是PHP8的一个新特性,意为只读。当我们对一个属性进行readonly类型声明后,该属性初始化后就只可读而不可更改。
例:
<?php
class Student {
// 声明属性 姓名和学号public string $name;
public int $stuNo;
//声明readonly类型public readonly string $school;
// 构造方法,对象实例化时调用public function __construct(string $name, int $stuNo,string $school) {
$this->name = $name;
$this->stuNo = $stuNo;
$this->school = $school;
}
// 声明方法public function goToSchool() : void {
echo "姓名:".$this->name.",学号:".$this->stuNo.",学校:".$this->school."\n";
}
}
$wang = new Student("王",1010,"清华大学");
$wang->goToSchool();
//当我们修改没有readonly的属性时
$wang->stuNo = 1011;
$wang->name = "王大壮";
$wang->goToSchool();
// 当我们试图修改readonly的school属性时
$wang->school = "北大";
$wang->goToSchool();
运行结果:
小测验
一个基于php-cli模式开发的学生管理系统
代码:
<?php
class Student {
// 声明属性 姓名和学号public string $name;
public int $stuNo;
//声明readonly类型public readonly string $school;
// 构造方法,对象实例化时调用public function __construct(string $name, int $stuNo,string $school) {
$this->name = $name;
$this->stuNo = $stuNo;
$this->school = $school;
}
// 声明方法public function goToSchool() : void {
echo "姓名:".$this->name.",学号:".$this->stuNo.",学校:".$this->school."\n";
}
}
function getInput() {
return trim(fgets(STDIN)," \t\n\r\0\x0B");
}
function addStudent(&$stuArr) {
echo "请输入学生姓名:\n";
$name = getInput();
echo "请输入学生号码:\n";
$stuNo = getInput();
echo "请输入所属学校:\n";
$school = getInput();
$stu = new Student($name,$stuNo,$school);
$stuArr[$name] = $stu;
}
function check($stuArr,$name) {
if(empty($stuArr)) {
return false;
}
if(empty($name)) {
return false;
}
if(!isset($stuArr[$name])) {
return false;
}
return true;
}
function showStudent($stuArr,$name) {
if(empty($name)) {
foreach ($stuArr as $stu) {
$stu->goToSchool();
}
return;
}
if(!check($stuArr,$name)) {
echo "输入信息有误!请重试!\n";
return;
}
if(isset($stuArr[$name])) {
$stuArr[$name]->goToSchool();
}
}
function delStudent($stuArr,$name) {
if(!check($stuArr,$name)) {
echo "输入信息有误!请重试!\n";
return;
}
unset($stuArr[$name]);
}
function main() {
$stuArr = [];
while (true) {
echo "请输入操作内容:\n 1 添加学生\n 2 查看学生\n 3 删除学生\n";
$contrl = getInput();
switch ($contrl) {
case 1:
addStudent($stuArr);
break;
case 2:
echo "请输入要查看的学生姓名,如为空则显示所有学生信息:\n";
$name = getInput();
showStudent($stuArr,$name);
break;
case 3:
echo "请输入要删除的学生姓名:\n";
$name = getInput();
delStudent($stuArr,$name);
break;
default:
break 2;
}
}
}
main();
运行结果:
原文:PHP8入门指南】初识类与对象