05 php面向对象基础01
1. 简介
1.1 面向过程编程
即将要解决的问题(功能需求)分解成具体的步骤,然后通过函数编程实现每一个步骤,最后通过函数规定好的顺序调用完成。
这种编程思想的优点就是能够针对步骤拆分,进行模块化封装(函数),然后可以实现代码复用,从而节省开发成本。但是此方式编程的缺点就是不够灵活维护,流程一旦确定就必须按照既定方式执行到底
1.2 面向对象编程
面向对象编程也叫做OOP编程,是一种基于面向过程的开发思想。
与面向过程强调分解事务步骤相似,面向对象更需要追求事务操作的“主体”,也就是对象
。
对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。
在现实世界里我们所面对的事情都是对象,如计算机、电视机、自行车等
对象的主要三个特性:
1. 对象的行为:可以对 对象施加那些操作,开灯,关灯就是行为。
2. 对象的形态:当施加那些方法是对象如何响应,颜色,尺寸,外型。
3. 对象的表示:对象的表示就相当于身份证,具体区分在相同的行为与状态下有什么不同
1. 面向对象编程是一种编程思想,与技术无关
2. 面向对象编程的本质是增加数据和功能的操作主体,即对象
3. 面向对象中所有的数据和功能都是由主体(对象)来调用和操作
面向对象思维的实现,就是利用面向对象提供的关键字和代码规范来进行编程,而这里面最核心的两个部分就是类class和对象object
2. 面向对象基础关键字
2.1 类class
定义了一件事物的描述特点。是定义面向对象主体的最外层结构,用来包裹主体的数据和功能(函数)
类的定义包含了数据的形式和对数据的操作
2.2 对象
对象是类的实例,是类实例化(new)产生的结果
2.4 类成员
类成员指类class结构中的所有内容,主要包含3种:属性、方法和类常量
2.4.1 方法method:成员函数、成员方法
定义在类内部的函数,可以用于访问对象的属性
2.4.2 属性property:成员变量
定义在类内部的变量
该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化对象后,该变量即可成为对象的属性
2.4.3 类常量const
定义在类内部的常量
2.5 继承
继承性是子类自动共享父类的数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。
2.6 父类
一个类被其他类继承,可以将该类称为父类、基类或超类
2.7 子类
一个类继承其他类称为子类,或派生类
2.8 多态
多态性是指相同的操作或函数、过程可作用于多种类型的对象上,并获得不同的结果。
不同的对象,收到同一消息可以产生不同的结果,这种现象就是多态性
2.9 抽象性
抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是一种抽象,它反映了于应用有关的重要性质,而忽略其他一下无关内容
任何类的划分都是主观的,但必须与具体的应用有关
2.10 封装
封装是指将现实世界中存在的某个客体的属性与行为绑定在一起,并放置为一个逻辑单元内
2.11 构造函数
主要用来在创建对象时,初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中
2.12 析构函数
析构函数与构造函数相反,当对象结束其生命周期时,系统自动执行析构函数。析构函数往往用来做 清理善后的工作
3.类
3.1 定义
-
创建类: 使用 class 关键字后加上 类名 ,其主要包含:成员变量(属性),成员方法(成员函数)和类常量
-
类是一种结构,不会自动运行,也不能输出
-
一般是驼峰命名法
-
实例化:就是类产生对象的一个过程
-
通过new 类名实例化对象得到类的具体对象(具象),可以通过new实例化无限个对象
-
类结构中只能有三种成员,不限数量,其他代码需要写到方法里面,否则报错
-
类中属性和方法的访问方式都是通过对象来调用:$对象->属性名/方法名();注意属性名不带$符号
-
类中定义属性不能直接使用属性名,需要使用符号public修饰
3.2 类成员
定义和访问
// 1. 定义
class 类名{
# 类常量,可以有多个
const 常量名=值;
# 属性(变量),可以有多个
[public] $属性名 [=值]; # 可以赋值,也可以不赋值
# 方法,可以多个
[public] function 方法名([形参列表]){
# 方法体(返回值)
}
}
// 2. 访问:对象访问属性和方法,都使用 ->
# 实例化
$object=new 类名();
# 属性访问
$object->属性名
# 方法访问
$object->方法名([实参列表])
成员变量
成员变量的访问:成员变量必须通过对象才能进行访问,也就是需要先通过实例化得到对象,然后通过对象实现对成员变量的增删改查:访问语法:$对象名->属性名
成员方法
就是在类结构{}下定义的函数
成员方法访问:成员方法也是需要通过对象进行访问的,访问语法为:$对象名->方法名字();
类常量
类常量是在类结构{}下定义的常量,关键字const
类常量不是由实例化对象来进行访问,可以通过类访问
<?php
// 定义一个网站类
class mySite
{
/* 成员变量 链接地址和标题*/
public $url;
public $title = '默认值';
// 成员函数
function showInfo()
{
echo '显示信息:' . $this->title;
}
// 成员常量:不可通过实例对象访问
const API = 3.14;
}
// 实例化对象
$s1 = new mySite;
// 赋值
$s1->url = 'www.baidu.com';
$s1->title = '百度一下';
// 新增一个属性
$s1->desc = '网站描述';
// 访问成员变量
echo $s1->url;
echo $s1->title;
echo $s1->desc;
// 访问 实例方法
$s1->showInfo();
3.3 范围解析操作符
范围解析操作符,由两个冒号组成“::”,是专门用于实现类成员操作的,实现类直接访问类成员
用来访问类常量:
类名::常量名
<?php
class Saler{
//类常量
const PI = 3.14;
}
echo Saler::PI; //输出3.14
3.5 静态成员static
- 静态成员,使用static关键字修饰的类成员,该成员可以直接通过类访问,不用实例化对象
- PHP静态成员主要有两种,静态属性和静态方法
- 静态属性不能通过实例化的对象来访问,但静态方法可以,一般不推荐
- 由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用
- 静态成员也收访问修饰限定符的限定,访问权限与普通属性和方法的限制一样
- 静态成员的访问效率比非静态成员高,但是对象的特点是多元化,静态的特点是单一化
<?php
class Foo
{
// 静态属性
public static $my_static = 'foo属性';
// 静态方法本质是给类访问,所以不允许在静态方法内部使用$this对象
public static function staticValue()
{
// echo $this; // 报错,静态方法内部不能使用 $this
// 通过self访问 成员变量
return self::$my_static;
// 或者
// return Foo::$my_static
}
}
// 直接类访问(静态属性):不需要实例化类class
echo Foo::$my_static;
// 直接类访问(静态方法):不需要实例化类class
echo Foo::staticValue();
// 访问 静态方法,虽然也可以通过实例化对象访问,但是一般不建议
$foo = new Foo();
echo $foo->staticValue();
3.6 self关键字
在类的内部(方法里面)使用,代替类名的一种写法,一般与 ::
搭配使用
- 在方法的内部,代替类名使用
- 一般用来在类内部访静态属性,类常量也可以
- 在类内部用来实例化对象new self()(代替类名:new 类名())
self:代替类名,与范围解析操作符::
一起使用的
<?php
class Saler
{
// 静态属性
private static $count = 0; // 私有,不允许外部直接访问
// 静态方法
public static function showClass()
{
echo Saler::$count;
// 代替类名,与 :: 一起使用
echo self::$count;
}
}
Saler::showClass();
在类的内部方便实例化对象:比如构造函数被私有化后,在类的外部没法实例化对象,此时我们就可以通过在类的内部实现对象的实例化来实现外部对类的
<?php
class Saler
{
private function __construct() {} // 私有,外部没法实例化对象了
// 静态方法
public static function showClass()
{
return new Saler(); // 使用 类名 实例化
return new self(); // 使用 关键字self 实例化
}
}
$s1 = Saler::showClass(); // 实例化对象
var_dump($s1);
// $s1=new Saler() // 报错,因为构造函数被私有化了
4. 对象
4.1 定义
对象是类的实例,是类实例化(new)产生的结果,可以使用 new 运算符来实例化该类的对象
可以通过new实例化无限个对象
5. 访问修饰符
访问修饰限定符,是一种用在属性或者方法前的修饰关键字,是用来控制属性或者方法的访问位置的。
在PHP中访问修饰限定符分为三种:public、protected和private
访问修饰限定符不只是限定属性,也用来限定方法:但是属性必须写修饰符,方法可以不写,默认是public
概念:
- 类内部:是指类定义的内容内部,即类名后{}内部
- 类外部:是指类定义的外部内容,即类名后{}之外的所有地方
- 类成员的访问权限控制有:内部访问(私有)private、链内部访问(受保护protected和全部访问(公有)public
public(公有):任何地方都可以访问
公有的类成员可以在任何地方被访问
所修饰的内容(属性或者方法),可以在当前类的内部访问,也可以在类的外部访问
<?php
class Saler
{
//公有属性
public $count = 100;
}
$s = new Saler();
echo $s->count; // 正常输出100
protected(受保护):自身、子类和父类访问
可以被其自身以及其子类和父类的内部访问
可以在子类的内部访问,不可以在子类的外部访问
private(私有):只能当前类的内部访问
只能在当前类的内部
访问
<?php
class Saler
{
//公有属性
private $count = 100;
}
$s = new Saler();
echo $s->count; //错误:私有属性不允许在类外访问
<?php
// 定义类
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
// 定义一个子类 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
6. 类内部对象 $this
:指向调用该方法的对象
内部对象:$this
类成员方法的内部内置的一个对象,会自动指向调用该方法的对象
$this
存在方法内部,仅限内部使用,所以相当于在类的结构内部
- 可以访问任意修饰符修饰的成员
- 私有成员都是通过公有方法来实现访问的
类内部对类成员的访问也是通过 $this
内部对象访问的
<?php
// 定义类
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello()
{
var_dump($this);
// $this访问类的内部成员,都可以访问
// $this的指向:调用该方法的对象,即$obj
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
$obj->printHello(); // 输出 Public、Protected 和 Private
7. 构造函数和析构函数
7.1 构造函数:__construct()
-
是一种类结构特有的特殊方法,在对象实例化之后,对象立即自动调用该构造方法
-
主要作用是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中
-
一旦构造方法拥有了形参,那么对象在调用该方法的时候就需要传入对应的实参
<?php
// 定义类
class mySite
{
public $url;
public $title;
// 构造函数,实例化的时候,自动调用
function __construct($url, $title)
{
$this->url = $url;
$this->title = $title;
}
}
// 实例化对象,并赋值
// 在实例化对象的时候,会自动调用 构造函数,实现数据的赋值
$obj = new mySite('www.baidu.com', '百度一下');
var_dump($obj);
7.2 析构函数:__destruct
- 与构造函数相反,当对象结束其生命周期时或在被销毁时(例如对象所在的函数已调用完毕),系统自动执行析构函数
- 析构方法是用来对象销毁自身所占用的资源
- PHP中脚本执行结束,系统会自动回收所有资源,因此一般PHP中很少使用析构方法
<?php
class MyDestructableClass {
function __construct() {
print "构造函数\n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "销毁 " . $this->name . "\n";
}
}
$obj = new MyDestructableClass();
?>
输出结果:
构造函数
销毁 MyDestructableClass
8. 对象传值:引用传递
对象传值,将保存对象的变量赋值给另外一个变量,在PHP中,对象的传值是引用传递的:即一个对象变量赋值给另外一个变量,两个变量指向同一个对象的内存地址,即只有一个对象
<?php
class Site
{
public $name;
function __construct($name
)
{
$this->name = $name;
}
}
// 实例化对象
$s1 = new Site('小王');
$s2 = $s1; // 将对象$s1赋值给$s1,s1和s2指向同一块内存地址
var_dump($s2);
// 给对象s2赋值,s1对象中的name也会发生变化,因为对象传值是引用传递
$s2->name = '小丽';
var_dump($s1);
9. 对象克隆clone
克隆对象clone,即通过已有的一个对象复制一个新的同样的对象,但是两者之间并非同一个对象,克隆出来的对象与原始对象是2个不同的内存地址
对象克隆是通过clone关键字实现
- 对象可以通过克隆来得到新的对象(以前只有实例化)
- 克隆出来的对象会自动调用类中对应的__clone()方法(如果有)
- 可以通过私有化克隆方法来实现禁止外部对象克隆
<?php
class Saler
{
//属性
public $count;
private $money;
}
// 实例化
$s1 = new Saler();
$s1->count = 1;
// 克隆
$s2 = clone $s1;
$s1->count = 3; // 修改对象s1的count值,s2中不会变化
// $s1和$s2不是同一个对象
var_dump($s1);
echo '</br>';
var_dump($s2);
对象在实例化的时候会自动调用存在的构造方法_construct()
,同样的,在类的内部,PHP允许定义一个_clone()
的方法,在对象被克隆后,新克隆出来的对象会自动调用_clone()
<?php
class Saler
{
//属性
public $count;
private $money;
//克隆方法
public function __clone()
{
var_dump($this); // 编号为2,代表是克隆出来的对象
$this->count++;
}
}
//实例化
$s1 = new Saler();
$s1->count = 1;
// 克隆:克隆对象后,会自动调用 __clone方法
$s2 = clone $s1;
如果不允许对象被克隆,可以将_clone()
方法私有化
<?php
class Saler
{
//属性
public $count;
private $money;
// 私有化克隆方法
private function __clone() {}
}
// 实例化
$s1 = new Saler();
$s1->count = 1;
// 克隆
$s2 = clone $s1; //致命错误:不允许对象在外部访问一个私有方法
10. 类的加载
类的加载,本质是因为类的访问必须先保证类在内存中已经存在,所以需要在用类之前,必须将类所在的PHP文件加载到内存
一般情况下,类的定义都是封装在单独的文件中,在使用的时候,才会被加载到对应的文件中
分类:手动加载和自动加载
- 手动加载:在需要使用类之前,通过include将包含类的文件引入内存
- 自动加载:提前定义好类结构和位置,写好引入类文件代码,在系统需要类,而内存中不存在类的时候,让写好的加载类的代码执行。(本质上就是:自动运行:实例化对象的时候,自动运行写好的加载类的代码),一般推荐使用自动加载
10.1 手动加载
手动加载:在要访问某个类之前,使用文件包含的方式,将类所在的文件加载进来
// 类文件:Saler.php
<?php
class Saler {}
?>
// 应用文件:useSaler.php
<?php
// 使用Saler类需要先包含Saler类所在的文件
// 先判定是否存在类
if (!class_exists('Saler')) {
include 'Saler.php';
}
$s = new Saler();
10.2 自动加载
10.2.1 系统函数__autoload
:不推荐
自动加载是PHP提供的一种加载机制
:即实现定义一个函数_autoload()
,然后当系统需要使用类,而内存中又不存在的时候,系统就会自动调用_autoload()
函数来加载类文件
定义自动加载:在实例化对象的时候,自动触发该方法
<?php
<?php
// 定义自动加载:在实例化对象的时候,自动触发该方法
function __autoload($classname)
{
// $classname 表示的是类名,不需要传参,在实例化对象的时候,类名会自动传递过来
echo '执行自动加载:__autoload' . $classname;
if (!class_exists($classname)) {
include $classname . '.php';
}
}
new Saler();
10.2.2 注册机制spl_autoload_register
--推荐
注册机制,将用户自定义的函数,放到系统内部,使用spl_autoload_register
将自定义函数注册到系统内部。本质与``_autoload()`还是一样的
<?php
// 定义自动加载
function my_autoload($classname)
{
// $classname类名
echo '执行自动加载:__autoload' . $classname;
if (!class_exists($classname)) {
include $classname . '.php';
}
}
// 将 my_autoload自定义函数,注册为 自动加载函数,就把该函数注册到了系统内部
spl_autoload_register('my_autoload');
// 在实例化对象的时候,自动触发了 my_autoload 方法
new Saler();
11 封装一个数据操作类
类
<?php
// 封装数据库操作类
// 链接数据库:主机地址 端口 账户 密码 数据库 字符集
class Sql
{
// 构建属性:数据库初始化资源私有,不需要外部访问
// 主机地址
private $host;
// 端口
public $port;
// 账户
private $user;
// 密码
private $pass;
// 数据库名
private $dbname;
// 字符集
private $charset;
// 保存连接对象
private $link;
// 记录错误信息--对外保留
public $error;
// 受影响行数
public $affected_rows;
// 查询结果记录数
public $num_rows;
// 初始化数据:使用数组接收
public function __construct($info = array())
{
//初始化:确保用户传入了数据,否则使用默认值
$this->host = isset($info['host']) ? $info['host'] : 'localhost';
$this->port = isset($info['port']) ? $info['port'] : '3306';
$this->user = isset($info['user']) ? $info['user'] : 'root';
$this->pass = isset($info['pass']) ? $info['pass'] : 'root';
$this->dbname = isset($info['dbname']) ? $info['dbname'] : 'mydb';
$this->charset = isset($info['charset']) ? $info['charset'] : 'utf8';
// 用户一旦实例化对象,就自动创建数据库的链接
$this->sql_connect();
$this->sql_charset(); // 设置字符集
}
// 1. 实现连接认证功能
private function sql_connect()
{
// @错误抑制符
$this->link = @mysqli_connect($this->host, $this->user, $this->pass, $this->dbname, $this->port);
if (!$this->link) {
$this->error = '数据库连接失败 ' . mysqli_connect_error() . ' in ' . mysqli_connect_errno();
die($this->error);
return false;
}
return true;
}
// 2. 设置字符集
private function sql_charset()
{
$res = @mysqli_set_charset($this->link, $this->charset);
if (!$res) {
$this->error = '字符集设置失败 ' . mysqli_error($this->link) . ' in ' . mysqli_errno($this->link);
die($this->error);
return false;
}
return true;
}
// 校验sql执行
private function sql_check($sql)
{
$res = @mysqli_query($this->link, $sql);
if (!$res) {
$this->error = @mysqli_error($this->link) . ' in ' . mysqli_errno($this->link);
return false;
}
return $res;
}
// 3. 写操作:新增、删除、更新
public function sql_exec($sql)
{
$res = $this->sql_check($sql);
if (!$res) return $res;
// 保存受影响的行数
$this->affected_rows = $this->link->affected_rows;
// 返回执行结果
return $res;
}
// 3. 查操作:一条数据和多条数据
// $all代表是否获取多条记录,默认true 获取所有记录
public function sql_query($sql, $all = true)
{
// 执行sql检查
$res = $this->sql_check($sql);
if (!$res) return $res;
// 查询结果记录数
$this->num_rows = $res->num_rows;
// 解析其中的结果:根据用户需求获取一条或者多条记录
if ($all) {
//获取全部:mysqli_result::fetch_all(MYSQLI_ASSOC)表示返回关联数组(默认是索引)
return $res->fetch_all(MYSQLI_ASSOC);
} else {
// 获取一条:mysqli_result::fetch_assoc()
return $res->fetch_assoc();
}
}
// 4. 获取上一次自增长操作id
public function sql_insert_id()
{
return mysqli_insert_id($this->link);
}
}
使用
<?php
// 类的加载
if (!class_exists('Sql')) {
include 'sql.php';
}
// 1. 连接本地数据库
$dbArray = array();
// 2. 实例化对象:自动连接数据库
$db = new Sql($dbArray);
// echo '<pre>';
// var_dump($db);
// 3. 查询最新的前3条数据
$sql = 'SELECT * from news LIMIT 3';
$con = $db->sql_query($sql);
echo '<pre>';
var_dump($con, $db->num_rows); // $db->num_rows:受影响的行数
// // 4. 插入一条数据
// $sql = "INSERT into news VALUES(default,'1130标题','1130内容',default,default,default)";
// $res = $db->sql_exec($sql);
// var_dump($res); // 返回true
// echo $db->sql_insert_id(); // 返回 最新一条插入数据的id
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!