_destruct 析构函数(很少几乎不用)
- 析构函数是一种特殊的方法,它在对象被销毁时自动调用
- 它可以用来执行一些清理操作,例如释放资源或关闭数据库连接
- 当对象不再被引用或脚本执行结束时,析构函数会被自动调用
php
<?php
class myClass
{
public function say($i)
{
echo "saying-", $i;
}
public function _destruct()
{
echo "析构函数被调用\n";
}
};
$obj = new myClass();
$obj->say(1);
//执行其他操作for
for ($i = 0; $i < 10; $i++) {
if ($i == 5) {
unset($obj); //销毁对象
}
if ($obj) { //Warning: Undefined variable $obj
$obj->say($i);
} else {
echo "对象已被销毁\n";
}
}
unset 销毁变量
语法
php
unset(mixed $var, mixed ...$vars): void
参数
可以是多个销毁参数,参数类型无限制
返回值
没有返回值
注意
unset在php中不是函数,而是一个语言结构类似于echo这种语法结构
插件
vscode 可安装Code Runner

注意:Code Runner 默认调用 php 命令,确保系统 PATH 中已包含 PHP。
则可直接右键编辑器中的 PHP 文件,选择 Run Code 如图:

其他需要安装的插件:
-
PHP CS Fixer
自动格式化 PHP 代码,让你的代码风格更统一、整洁。
-
PHP Intelephense
是一个非常流行的 VSCode 插件,主要用于提升 PHP 开发体验。它的主要功能包括:
-
智能代码补全
自动提示函数、变量、类名等,输入时更高效。
-
语法和错误检查
实时检查你的 PHP 代码是否有语法错误或潜在问题。
-
跳转和查找定义
可以快速跳转到函数、类、变量的定义,方便阅读和维护代码。
-
重构和重命名
支持安全地重命名变量、函数等,自动更新相关引用。
-
代码片段和文档提示
输入函数时会显示参数和相关文档说明,帮助你理解用法。
-
查找引用
可以查找某个变量或函数在项目中的所有引用位置。
3.PHP Namespace Resolver
主要用于帮助你管理和自动处理 PHP 代码中的命名空间(namespace)和 use 语句。它的主要功能包括:
-
自动导入类、函数、接口等
当你在代码中使用某个类或函数时,插件可以自动在文件顶部添加对应的use语句,无需手动输入完整命名空间。
-
优化和排序 use 语句
可以一键整理文件顶部的所有use语句,去除未使用的引用,并按字母顺序排序,让代码更整洁。
-
快速跳转和查找
支持通过命名空间快速跳转到类、接口、函数的定义,提高开发效率。
-
重构命名空间
当你移动文件或更改类名时,插件可以自动更新相关的命名空间和use语句,避免出错。
4.PHP Debug
用于在 VSCode 里调试 PHP 代码,可以设置断点、单步执行、查看变量,非常适合排查问题。
参考文档:https://code.visualstudio.com/docs/languages/php
static静态变量和self
【静态】指的是无需对类进行实例化,就可以直接调用这些属性和方法
所有对静态变量进行的操作都会对所有对象起作用
静态属性使用 范围解析操作符 ( :: )访问,不能通过对象操作符( -> )访问。
php
class myClass2
{
public static $cat = 'yy';
public static function sayHello()
{
echo self::$cat;
echo static::$cat;
}
}
echo myClass2::$cat;
myClass2::sayHello();
调用语法:
对象类名::静态变量/静态方法()
注意:
不推荐用 $obj->静态方法() 或 $obj->静态变量 的方式调用(虽然语法允许,但不推荐)。
不推荐使用伪变量 t h i s : : this:: this::cat,由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用
参考:
https://www.php.net/manual/zh/language.oop5.static.php
https://www.php.net/manual/zh/language.oop5.paamayim-nekudotayim.php
类常量
使用场景:所有对象公用一个属性
静态属性与类常量相似,唯一的区分是类常量不可以更改,静态属性可以更改
语法
使用const 关键字定义
php
<?php
class myClass2
{
const PI = 3.14;
public function sayHello()
{
echo self::PI . PHP_EOL;
}
}
echo MyClass2::PI;
static 静态方法
静态方法
- 可以调用非静态方法,非静态变量
- 可以调用静态方法,静态变量
php
<?php
class myClass
{
const PI = 3.14;
public $name = "张三";
public function eat()
{
echo $this->name . "在吃饭";//非静态方法中可以使用$this表示实例化对象
}
//静态方法
public static function sayHello()
{
echo self::PI . PHP_EOL;
echo (new self)->eat(); //因为静态方法里没有$this,所以需要用new self来实例化对象
echo self::run(); //调用静态方法
}
public static function run()
{
echo 'run ';
}
}
echo myClass::PI;
echo myClass::sayHello();
操作符
-> 对象操作符
=>键值对分隔符/键值分隔符
https://www.php.net/manual/en/language.types.array.php
范围解析操作符 ( :: )
- 范围解析运算符(也称作 Paamayim Nekudotayim)或更简单地说是双冒号,是一种允许访问类或其中一个父类的常量、static 属性或 static 方法的标记。此外,静态属性或方法也可以通过后期静态绑定来覆盖
类的继承(extends)
指可以创建一个新的类,该类继承extends了父类的属性和方法,并且可以添加自己的属性和方法
通过继承,可以避免重复编写相似的代码,并且可以实现代码的重用
注意:继承不一定能访问
php
<?php
class Animal
{
public $name = '小动物';
protected $age = 3;
private $birth = '2026';
public function __construct($name)
{
$this->name = $name;
}
public function eat()
{
echo $this->name . '正在吃';
}
}
class Cat extends Animal
{
public function show()
{
echo $this->name;
echo $this->age; //protected-内部可以访问但是实例化不能访问
// echo $this->birth; //除父继承的类外无法访问
}
public function meow()
{
echo $this->name . '正在喵喵叫';
}
}
// var_dump(new Animal);
// var_dump(new Cat);
// $cat = new Cat; //
// echo $cat->name;
// echo $cat->show();
$cat = new Cat('小猫');
var_dump($cat);
$cat->eat(); //继承父类方法
$cat->meow();//调用子类方法
-
在php中new Cat和new Cat()都可以实例化对象,去呗只是语法上的简化
-
如果类的构造函数没有参数,括号可以省略
-
如果类的沟槽函数有参数,必须写括号并传参,例如new Cat('小黑')
方法和属性重写
如果从父类继承的方法或属性不能满足子类的需求,可以对其进行改写
Final 关键字
作用
- 防止类被继承
- 防止类的方法被重写
如果在一个类前面加final,那么这个类就不能被继承
final class myClass {}
如果在一个方法前面加final,那么这个方法就不能被重写
final public function eat(){echo $this->name."在吃饭"}
实例
php
<?php
final class Animal
{
public $name = '小动物';
protected $age = 3;
private $birth = '2026';
public function __construct($name)
{
$this->name = $name;
}
final public function eat()
{
echo $this->name . '正在吃';
}
}
//一般是一些库会用到 防止吧父类方法覆盖
class Cat extends Animal //Class Cat cannot extend final class Animal 此类不能被继承
{
public function show()
{
echo $this->name;
echo $this->age; //protected-内部可以访问但是实例化不能访问
// echo $this->birth; //除父继承的类外无法访问
}
public function eat() //Method 'Cat::eat()' cannot override final method 'Animal::eat()'.报错方法不能被重写
{
echo $this->name . '正在大吃大喝';
}
public function meow()
{
echo $this->name . '正在喵喵叫';
}
}
// var_dump(new Animal);
// var_dump(new Cat);
// $cat = new Cat; //
// echo $cat->name;
// echo $cat->show();
$cat = new Cat('小猫');
var_dump($cat);
$cat->eat(); //继承父类方法
$cat->meow();//调用子类方法
调用父类方法
Parent::
Parent::_construct()
php
<?php
class Animal
{
public $name = '小动物';
protected $age = 3;
private $birth = '2026';
public function __construct($name)
{
$this->name = $name;
}
public function eat()
{
echo $this->name . '正在吃';
}
}
class Cat extends Animal
{
public function __construct($name, $age = 10)
{
parent::__construct($name);
$this->age = 5;
}
public function eat()
{
echo $this->name . '正在大吃大喝';
}
public function meow()
{
parent::eat(); //调用父类方法
echo $this->name . '正在喵喵叫';
}
}
$cat = new Cat('小猫');
var_dump($cat);
$cat->meow();//调用子类方法
静态延迟绑定static(用的比较少,了解即可)
是指在运行时根据实际调用的类来确定惊天方法或属性的绑定
语法:static:$name
php
<?php
class Animal
{
protected static $name = '小动物';
public static function eat()
{
echo self::$name . '正在吃'; //根据当前父级对象来调用属性
echo "----";
echo static::$name . '正在吃'; //根据当前运行时的对象来调用属性 可能不是父级对象的$name
}
}
class Cat extends Animal
{
protected static $name = '小猫';
}
// Animal::eat(); //调用静态方法 ::
Cat::eat();
self:: 和 static:: 的区别
self::
- 绑定在定义它的类(编译时绑定,叫"早绑定")。
- 无论是通过父类还是子类调用,
self::总是指向当前代码所在的类。 - 在例子里,
self::$name总是指向Animal里的$name。
static::
- 绑定在实际调用的类(运行时绑定,叫"晚绑定"或"后期静态绑定")。
- 通过哪个类调用,
static::就指向哪个类。 - 在例子里,
static::$name如果通过Cat::eat()调用,就指向Cat里的$name。
类的多肽
- 多态性运行不同类的对象对相同的消息做出不同的响应
- 多态性通过重写(覆盖)和方法重载来实现
- 方法重写是指在同一个类中根据参数个数或类型不同来实现不同的功能
- 需要注意的是,多肽性指适用于继承关系的类,子类必须重写父类的方法才能实现多态性
php
<?php
class Animal
{
protected $name = '动物';
public function makeSound()
{
echo "$this->name 在吼叫";
}
}
class Dog extends Animal
{
protected $name = "小狗";
public function makeSound()
{
echo "$this->name 在汪汪叫";
}
}
class Cat extends Animal
{
protected $name = "小猫";
public function makeSound()
{
echo "$this->name 在喵喵叫";
}
}
$animal = new Animal();
$animal->makeSound();
$dog = new Dog();
$dog->makeSound();
$cat = new Cat();
$cat->makeSound();
方法重载
php
$arg = func_get_args();
$numArgs = func_num_args();
实例
php
<?php
function test()
{
$arg = func_get_args();
$numArgs = func_num_args();
var_dump($arg);
echo '我有' . $numArgs . '个参数' . PHP_EOL;
var_dump($numArgs);
switch ($numArgs) {
case 0:
echo '我没有参数' . PHP_EOL;
break;
case 1:
echo '我有1个参数' . PHP_EOL;
break;
default:
echo '我有' . $numArgs . '个参数' . PHP_EOL;
break;
}
}
test(1, 2, 3, 4);
class Animal
{
public function makeSound()
{
echo "动物在后脚";
}
}
class Cat extends Animal
{
public function makeSound()
{
$numArgs = func_num_args();
switch ($numArgs) {
case 0:
echo '我没有参数' . PHP_EOL;
break;
case 1:
echo '我有1个参数' . PHP_EOL;
break;
default:
echo '我有' . $numArgs . '个参数' . PHP_EOL;
break;
}
}
}
$cat = new Cat();
$cat->makeSound("测试", "2");
接口
参考:https://www.php.net/manual/en/language.oop5.interfaces.php
Interface(接口)
php
<?php
interface Animals
{
public function a();
public function b();
}
接口是指一组方法的集合,不是类,不能被实例化
- 可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容
- 只可以使用public
- 通常用于定义一些规范,然改代码更加有条理,不易出错
例如:生活中的接口:手机通用接口type-c接口 (满足一定规范)
例如:小动物必须要吃饭和睡觉,否则就会死,这是必须的,每个小动物都必须有这两个方法
php
<?php
interface Animals
{
const name = '动物';
public function eat();
public function sleep($hour);
public static function jump();
}
//实现/遵循接口规范
class Cat implements Animals
{
public function eat()
{
echo "Cat 在吃饭";
}
public function sleep($hour)
{
echo "Cat 要睡" . $hour . "小时";
}
public static function jump()
{
echo "Cat 在跳";
}
}
$cat = new Cat();
$cat->eat();
$cat->sleep(18);
echo Cat::name;
echo Cat::jump();
一个类可以同时实现多个接口
php
<?php
interface Animals
{
public function eat();
public function sleep($hour);
}
interface Sports
{
public function run();
public function jump();
}
class Cat implements Animals, Sports
{
public function eat()
{
echo 'Cat 在吃饭';
}
public function sleep($hour)
{
echo 'Cat 要睡' . $hour . '小时';
}
public function run()
{
echo 'Cat 在跑';
}
public function jump()
{
echo 'Cat 在跳';
}
}
抽象类和抽象方法
和接口非常类似,使用它也是定义一种约束或规范,适合较大型的项目或库使用
抽象类语法
php
abstract class Animals{
}
- 抽象类是一种特殊类,只能被继承,不能被实例化
- 抽象类用于定义一组相关的方法,但这些方法的具体实现由继承它的子类完成
- 子类继承抽象类后,必须实现抽象类中的所有抽象方法
- 抽象类可以包含抽象方法和普通方法
抽象方法
php
abstract class Animals{
abstarct public function xxx();
abstarct public function xxx();
}
- 抽象方法是没有具体实现的方法,只有方法的声明,而不需要方法体
- 抽象方法只存在于抽象类中,不能在普通类中声明
- 可以使用protected 但不能使用private私有
php
<?php
abstract class Animal
{
abstract public function eat(); //抽象方法
abstract protected function sleep($hour); //抽象方法
public function run() //普通方法
{
echo 'Animal 在跑';
}
}
//通过子类继承抽象类,必须实现抽象方法
class Dog extends Animal
{
public function eat()
{
echo 'Dog 在吃东西';
}
protected function sleep($hour)
{
echo 'Dog 在睡觉' . $hour . '小时';
}
}
抽象类和接口的区别
1.抽象类可以包含费抽象房方法的视线,而接口只能包含方法的声明,没有方法的实现
2.类只能继承一个抽象类,但可以实现多个接口
3.抽象类可以有构造函数,而接口不能有构造函数
4.抽象类中的方法可以是public,protected和private(普通方法) 访问修饰符,而接口中的方法只能是public
5.子类继承抽象类时,必须实现抽象类中的所有抽象方法,否则也必须声明为抽象类。
抽象类更像"半成品模板",
接口更像"能力清单 + 规则说明书"。
抽象类更适合「强耦合继承链」,接口更适合「横向扩展」
这是架构设计里非常重要的一点。
- 抽象类
- 更像一条家族血脉
- 一旦继承,就被"绑定"在这条链上
- 接口
- 像技能徽章
- 你可以同时佩戴很多个
这也是为什么:
- 框架里大量用接口(解耦、扩展)
- 业务基类才会用抽象类(复用逻辑)
接口强调「约束」,抽象类强调「复用」
抽象类解决"我是谁,并且我已经帮你做好了一部分"
接口解决"你必须能做到什么,至于你怎么做到我不管"
trait关键字 实现复用
- 解决类的单一继承问题
- 可同时使用多个trait,用逗号隔开
- 把常用的,通用的代码抽离出来,写成trait
语法
Trait (特质)
php
<?php
trait TraitA
{
public function play()
{
echo 'TraitA 在玩';
}
}
trait TraitB
{
public function run()
{
echo 'TraitB 在跑';
}
}
class Person
{
use TraitA, TraitB;//一个对象可以实现多个特质
public function action()
{
$this->play();
$this->run();
}
}
$personA = new Person();
$personA->action();
和类的继承非常像,但是trait里面不能有类常量,且trait不能被实例化
-
trait中可使用抽象方法
php<?php trait Animal { protected $name; abstract function test(); public function __contruct($name) { $this->name = $name; } public function eat() { echo $this->name . "在吃饭"; } } class Cat { use Animal; function test() { echo "这是一个抽象方法的实现"; } public function play() { echo $this->name . "在玩耍"; } } $cat = new Cat('Tom'); $cat->eat(); $cat->play(); $cat->test(); -
trait中可使用静态属性和静态方法
php<?php trait A { static $age = 19; //静态属性 public static function TestA() //静态方法 { echo 'A里面的', __METHOD__; //返回对象方法名 } public function Test() { echo 'A里面的', __METHOD__; //返回对象方法名 } } trait B { use A; public function TestB() { echo 'B里面的', __METHOD__; } } class Tests { use B; } $test = new Tests(); $test->Test(); //A里面的A::Test echo Tests::$age; //19 echo Tests::TestA(); //A里面的A::TestA -
trait中可使用其他trait
php<?php trait A { public function Test() { echo 'A里面的', __METHOD__; //返回对象方法名 } } trait B { use A; public function TestB() { echo 'B里面的', __METHOD__; } } class Tests { use B; } $test = new Tests(); $test->Test(); //A里面的A::Test -
trait中可使用parent
php<?php class MainClass { public function main() { echo "这是主方法的" . __METHOD__; } } trait Animal { public function eat() { parent::main(); echo $this->name . "在吃饭"; echo __TRAIT__ . "在Trait中"; // __TRAIT__ 特性名称。特性名称包含声明它的命名空间(例如Foo\Bar)。 } } class Cat extends MainClass { use Animal; protected $name; public function __construct($name) { $this->name = $name; } public function meow() { echo $this->name . "在喵喵叫"; } } $cat = new Cat("小花猫"); $cat->eat();//这是主方法的MainClass::main 小花猫在吃饭 Animal在Trait中
同名冲突
当一个类同事引入了多个trait,并且这些trait中存在同名方法时,就会产生方法冲突
php
use A,B{
B::eat inteadof A;
//别名定义
A::eat as Aeat;
}
例如如下情况
php
<?php
trait A
{
public function eat()
{
echo '这是A的';
}
}
trait B
{
public function eat()
{
echo '这是B的';
}
}
class T
{
use A, B;
}
$t = new T();
$t->eat(); //Fatal error: Trait method B::eat has not been applied as T::eat, because of collision with A::eat 报错 因为有同名方法
解决方案
php
<?php
trait A
{
public function eat()
{
echo '这是A的';
}
}
trait B
{
public function eat()
{
echo '这是B的';
}
}
class T
{
use A, B {
B::eat insteadof A; // 使用B的eat方法 代替A的eat方法
A::eat as eatA; //给A的eat方法起个别名eatA
}
}
$t = new T();
$t->eat(); //会调用B的eat
$t->eatA();
as不仅可以重命名还可以改变权限 例如
php
<?php
trait A
{
public function eat()
{
echo '这是A的';
}
}
trait B
{
public function eat()
{
echo '这是B的';
}
}
class T
{
use A, B {
A::eat insteadof B; //使用A的eat方法
// B::eat as eatB; //给B的eat方法起个别名eatA
B::eat as protected eatB; //给B的eat方法起个别名eatA as 还可以改变访问权限
}
public $name = "b";
public function d()
{
echo $this->eatB();
}
}
$t = new T();
$t->eat(); //调用A的方法
$t->eatB(); //报错 因为eatB被protected修饰 Fatal error: Uncaught Error: Call to protected method T::eatB() from global scope
$t->d();