php 面向对象编程(class)之从入门到崩溃 基础篇
一、面向对象的发展历程
学习目标:理解面向对象编程思想,了解计算机编程语言的演变过程,掌握PHP面向对象的基础语法,使用面向对象编程思想和面向对象语法实现编程解决需求问题
编程语法发展史:计算机编程在历史的发展长河中,经历了多次版本变革
,变化的轨迹是伴随着硬件的发展和人们对于计算机的认知以及需求。
-
机器语言:即开发者(科学家)使用
0
和1
组成命令,然后在特定计算机上执行-
优点:执行效率高
-
缺点:开发难度大、移植性差、开发成本高
-
-
汇编语言:开发者使用简洁
英文字母
和符号
组成,让计算机读取后根据符号进行加工执行- 优点:指令简单明了、推广性高
- 缺点:移植性差、功能简单
-
高级计算机语言:开发者使用类似自然语言的
符号
组成,高级语言根据编程思想分为面向过程编程
和面向对象编程
两种,然后系统对程序代码进行编译(需要第三方编译器)然后执行- 优点:移植性强、可读性强、推广性非常高
- 缺点:执行效率降低
面向过程编程思想: 将要解决的问题(功能需求)分解成具体的步骤,然后通过函数编程实现每一个步骤,最后通过函数规定好的顺序调用完成
-
面向过程编程思想的优点
- 能够针对步骤拆分,进行模块化封装(函数)
- 可以实现代码复用,从而节省开发成本
-
面向过程编程思想的缺点
- 不够灵活维护,流程一旦确定就必须按照既定方式执行到底。
小结
- 计算机编程从对开发人员要求极高到要求不高,是一代代人坚持不懈的结果
- 面向对象编程是目前最为符合人类思维逻辑的一种编程思想
面向对象编程思想:面向对象编程也叫做OOP编程(Objected Oriented Programming),是一种基于面向过程的开发思想。与面向过程强调分解事务步骤相似,面向对象更需要追求事务操作的“主体”,也就是对象
-
面向对象编程是一种编程思想,不是一种具体技术
-
面向对象是在面向过程基础之上发展而来,因此也是一种模块化编程思想(有函数)
-
面向对象能够更加方便的实现代码的重复利用(适用于大型项目)
-
在面向对象思维中,任何动作的执行或者数据都属于对象(一切皆对象)
小结
- 面向对象编程是一种编程思想,与技术无关
- 面向对象编程的本质是增加数据和功能的操作主体,即对象
- 面向对象中所有的数据和功能都是由主体(对象)来调用和操作
1、面向过程编程思想原理
2、面向对象编程思想原理
二、面向对象基础
1、面向对象关键字说明
面向对象关键字:基于面向对象开发时,所用到的一些关键字,用来表明不同的结构或者类型
-
类:class,是定义面向对象主体的最外层结构,用来包裹主体的数据和功能(函数)。类是一类具有共性事务的代表,代表的是事务的共性。
-
对象:object,是某类事务的具体代表,也是实际数据和功能操作的具体单元,也被称之为实例(instance)
-
实例化:new,从一个抽象的概念得到一个符合抽象概念的具体实例的过程
-
类成员:member,指类class结构中的所有内容,类成员里有三种
- 方法:method,本质是在类class结构中创建的函数,也称之为
成员方法
或者成员函数 - 属性:property,本质是在类class结构中创建的变量,也称之为
成员变量
- 类常量:const,本质是在类class结构中创建的常量
- 方法:method,本质是在类class结构中创建的函数,也称之为
2、类的定义、实例化和对象
类:根据对象分析后得到的一种通用结构(分类)
- class关键字声明类
- 类名:自定义名字,通常首字母大写,一般多单词组成类使用驼峰法(大驼峰法)
- 大括号:类内部的结构(member,类成员)
class 类名{
}
- 实例化:类产生对象的过程
new 类名;
new 类名(); # 使用较多
- 对象(实例):根据类产生的某个具体存在的实体(instance),对象一般使用变量保存
$object = new 类名();
小结
- 通过class关键字 + 类名 +{}创建类
- 类是一种结构,不会自动运行,也不能输出
- 通过new 类名实例化对象得到类的具体对象
- 可以通过new实例化无限个对象
3、类成员
类成员:指直接定义在类结构{}内部的一级成员,即直接依赖{}的成员
- 类成员分类
- 成员变量(属性):给对象存储数据的变量
- 成员函数(方法):给对象调用解决问题的函数
- 类常量:属于类内部的常量,使用const关键字定义
- 属性和方法需要使用访问修饰限定符修饰,姑且使用public修饰
class 类名{
# 类常量(可以多个)
const 常量名 = 值;
# 属性(可以多个)
public $属性名 [ = 值]; # 可以赋值也可以不赋值,只声明
# 方法(可以多个)
[public] function 方法名([形参列表]){
# 方法体(返回值)
}
}
- 成员访问:属性和方法都属于对象访问,类常量和静态成员属于类访问
- 对象访问属性和方法,使用
->
- 类常量和静态成员,使用
::
- 对象访问属性和方法,使用
使用步骤:
- 声明类结构
- 明确类产生的对象是否需要有数据的存储:确定属性
- 明确类产生的对象是否需要函数实现功能:确定方法
- 明确类是否需要定义常量:确定类常量
- 对象实例化
- 类成员访问(属性和方法)
示例:
- 声明类结构
# 定义买家类:买家有姓名,有钱
class Buyer{
# 属性声明
$name; # 错误,类内部属性必须使用访问修饰限定符
public $name; # 正确:没有赋值
public $money = 0; # 正确:有赋值
# 类常量声明
const BIG_NAME = 'BUYER';
# 方法声明
function display(){
echo __CLASS__; # 魔术常量,输出类名
}
}
- 成员变量访问(属性和方法):成员必须通过对象才能进行访问,需要先通过实例化得到对象,然后通过对象实现对成员进行操作
# 实例化对象
$b = new Buyer();
# 访问属性
echo $b->money;
# 修改属性
$b->money = 1000;
# 删除属性
unset($b->name);
# 新增属性
$b->age = 20;
# 访问方法
$b->display();
注意
-
删除属性和新增属性通常使用较少,更多的属性操作是访问和修改
-
类常量不是由对象来进行访问,而是有类访问
-
属性和方法的使用都必须确保类中已经定义(属性可以新增)
- 类成员中:属性、类常量和方法都可以无限定义,但是定义的原则是相关性。除了以上三个类成员,不能在类结构{}中直接写其他任何代码
class Buyer{
echo __CLASS__; # 错误
define('PI',3.14); # 错误
if(true){ echo 'hello world'} # 错误
}
小结
1、PHP类结构中有且仅有三种成员:属性、方法和类常量,其他直接属于类的内容都会报错
2、类声明需要根据业务来确定类成员的存在和数量
3、类中属性和方法的访问方式都是通过对象来调用:$对象->属性名/方法名();注意属性名不带$符号
4、类中定义属性不能直接属性名,需要使用符号public修饰(访问修饰限定符中的一种)
4、访问修饰限定符
访问修饰限定符:用在属性或者方法前的修饰关键字,是用来控制属性或者方法的访问位置
- 访问修饰限定符分类
- public:公有,类内和类外都可以访问
- protected:受保护,只允许在相关类内部访问
- private:私有,只允许在定义类内部访问
- 属性必须有访问修饰限定符,方法可以没有访问修饰限定符(默认public)
示例:
- 公有成员访问
class Saler{
# 属性
public $count = 100;
# 方法
public function getCount(){
echo __METHOD__; # 魔术常量,显示当前方法名(包含类名)
}
function setCount(){
echo __METHOD__;
}
}
# 实例化对象
$s = new Saler();
# 访问(类外)
echo $s->count;
$s->getCount();
$s->setCount();
- 受保护和私有成员设定
class Buyer{
# 属性
protected $money = 10;
private $account = '6226000000000001';
# 方法
protected function getMoney(){
echo __METHOD__;
}
private function getAccount(){
echo __METHOD__;
}
}
# 实例化
$b = new Buyer();
echo $b->money; # 错误:当前属于类外部,不能访问
echo $b->account; # 错误:当前属于类外部,不能访问
$b->getMoney(); # 错误:当前属于类外部,不能访问
$b->getAccount(); # 错误:当前属于类外部,不能访问
总结
1、访问修饰限定符分为三种:public、protected和private,访问权限依次降低(类对成员控制权限依次增加)
2、访问修饰限定符限定的是成员到底在哪里能被访问,私有和受保护都只能在类内部访问,公有可以在任何地方访问(但都必须是对象去访问)
3、属性必须写清楚访问修饰限定符,方法可以省去(不建议),因为系统默认是public
5、类内部对象$this
内部对象:$this,方法内部内置的一个对象,会自动指向来调用方法的对象
- $this存在于方法内部(仅限内部使用),所以相当于在类的结构内部
- 可以访问任意访问修饰限定符修饰的成员
- 私有成员都是通过公有方法来实现访问(公有方法可以在类外部访问)
- 类内部对类成员的访问也需要通过对象才能访问,所以必须通过$this内部对象访问类成员
示例:
1、尝试在类内部方法中访问属性
class Saler{
# 属性
public $count = 100;
protected $discount = 0.8;
private $money = 100;
public function getAll(){
echo $count,$discount,$money; # 全部错误:提示未定义的“变量”
}
}
$s = new Saler();
$s->getAll();
注意:方法本质是定义在类内部的函数,因此受制于作用域的问题,在方法内部访问的变量系统认定为局部变量(必须内部定义或者参数传入),否则就会提示未定义
2、类内部访问类成员,需要通过对象来进行访问
class Saler{
# 属性
public $count = 100;
protected $discount = 0.8;
private $money = 100;
public function getAll(){
# 第一种访问方式
# 需要获取到对象名字:因为方法本身就是函数,访问外部全局变量可以通过global引入实现
global $s;
echo $s->count,$s->discount,$s->money; #正确输出
# 上述代码规定死了以后对象只能是$s,不能有其他对象或者其他命名,所以非常不友好
#第二种方式,使用内置对象$this访问,一般都使用这种方式
var_dump($this);
echo $this->count,$this->discount,$this->money; #正确输出
}
}
$s = new Saler();
$s->getAll();
注意:$this代表的是对象,而$this所在环境为类内部的方法内部,所以$this对象是在类内部访问,因此可以访问所有的属性和方法,不受访问修饰限定符限制
$this、class和new之间的关系原理
-
class是定义类结构,属于非执行段代码,因此会被加载到代码段(编译阶段)
-
new是实例化对象,先判定类在内存(代码段)是否存在
- 类不存在,报错;
- 类存在,将类内部的属性部分复制一份,然后在内存(堆区)开辟一块内存空间,将属性放到里面,同时内部有一个指针指向类的内存空间(代码段)
- 对象访问属性即访问的是对象空间里存储的部分
- 对象访问方法是对象通过内部指针找到类空间中的方法,然后在内存(栈区)开辟运行
-
$this是系统在方法内置的对象通用名字
- 对象在调用方法的时候,系统会自动找到对象所保存的内存地址(堆区),然后把地址赋值给$this
-
方法内部的$this就代表调用当前$this所在方法的外部对象
- $this的本质是函数内部的一个局部变量,只是系统自动对其进行赋值,而且一定是调用方法的对象本身
-
面向对象编程代码运行内存关系
小结
1、类内部方法内有一个内置对象$this,代表访问该方法的外部对象
2、类在实例化对象的时候要保证内存中有该类
3、一个类可以实例化多个对象,每个对象访问成员方法时,$this就代表对应对象
6、构造方法
构造方法:__construct(),是一种类结构特有的特殊方法,该方法由系统规定好,开发人员在定义的时候只需要抄一遍,有了构造方法的类在实例化对象之后,对象就会自动调用。
- 构造方法是一种魔术方法:魔术方法是会自动被触发,不需要手动调用的方法
- 构造方法的目标是为了实现对象的初始化
- 对象实例化之后会自动调用
- 构造方法通常是为了实现对象所需资源的初始化(属性、资源)
- 构造方法虽然为魔术方法,但本质依然是一个方法
- 受访问修饰限定符控制(对象的产生位置会发生改变)
- 对象可以选择调用(一般不会)
- 构造方法可以设定形参,形参对应的实参是在实例化对象的时候传入:new 类名(实参传递给形参)
示例:
1、构造方法实现:在类中增加一个方法__construct()即可
class Saler{
# 构造方法,实例化之后就自动调用
public function __construct(){
echo __CLASS__;
}
}
2、构造方法也是一个方法,不普通的地方在于,类实例化得到的对象会马上自动调用
# 实例化
new Saler(); # 输出Saler
小结
1、构造方法__construct()是一种系统内置的方法,该方法的特性是会在对象实例化之后,对象立即自动调用
2、构造方法的目的就是为了初始化资源,包含对象属性和其他资源
3、一旦构造方法定义好之后,且构造方法自带参数,那么就只能使用new 类名(参数列表)
方式才能正确实例化
4、构造方法可以当做普通方法由对象调用(不建议)
7、析构方法
析构方法:__destruct(),也是一种类结构中魔术方法,与构造方法一样,也是系统规定好,只需要开发人员抄一遍即可,对象在被销毁时会自动调用
- 析构方法是用来对象销毁时主动释放资源的
- 对象销毁
- 对象无变量指向(变量指向其他数据)
- 对象被主动销毁(unset销毁对象变量)
- 脚本执行结束(自动释放资源)
- PHP脚本执行结束会释放所有资源,所以一般较少使用析构方法
示例:
1、析构方法实现:类中增加一个__destruct()方法
class Saler{
# 析构方法
public function __destruct(){
echo __FUNCTION__;
}
}
2、析构方法调用:析构方法是在对象被销毁时自动,对象的“垂死挣扎”
# 实例化对象
$s = new Saler();
# 对象变量指向其他数据
$s = 1;
# 主动销毁对象变量
unset($s);
# 脚本执行结束自动释放
3、析构方法也是普通方法,可以由对象直接调用
# 接析构方法实现代码
$s = new Saler();
$s->__destruct(); # 思考:此时对象是否被销毁?
小结
1、析构方法是一种对象销毁时自动调用的方法
2、析构方法是用来对象销毁自身所占用的资源
3、PHP中脚本执行结束,系统会自动回收所有资源,因此一般PHP中很少使用析构方法
8、范围解析操作符(类常量访问)
范围解析操作符:由两个冒号组成“::”,是专门用于类实现类成员操作的,可以实现类直接访问类成员
- 范围解析操作符是用于给类(类名)访问类成员使用的
类名::类成员
- 范围解析操作符也可以被对象用来当做类使用(不建议使用)
$对象名::类成员
- 类常量只能被类访问
示例:
1、类常量的普通访问尝试:尝试使用对象进行访问
class Saler{
# 类常量
const PI = 3.14;
}
$s1 = new Saler();
echo $s1->PI; # 错误,$s1->PI最终转换的访问方式为:$PI,这个在类中并不存在
2、以上案例可以看出,对象无法访问类常量,那是因为类常量的定义本身就是用来给类访问的,对象是用来访问属性和方法的,类常量的访问方式为:类名::常量名
# 类+范围解析操作符访问类常量
echo Saler::PI; # 输出3.14
3、对象本身也依赖于类,因此也可以使用对象对类控制成员进行访问,需要使用范围解析操作符
$s = new Saler();
echo $s::PI; # 输出3.14
注意:以上方式能访问,但是不建议使用(以上方式也能看出,成员谁来访问,关键看用什么符号:①使用范围解析操作符::
就是类访问;②使用对象操作符号->
就是对象访问)
4、分析:类常量是固定的,而对象的属性是不同对象而不同的,成员方法简单的理解也是为属性本身进行加工的。因此有一些东西是专属于类的,而有部分内容是专门为对象提供的,所以就会有不同的成员拥有不同的访问方式
小结
1、类访问成员的方式是使用范围解析操作符“::”访问,由类名直接访问:类名::类常量
2、类本身是通过对同类对象的抽象而形成,所以属性和方法本身都是由对象来访问
3、类也需要有一些自身的数据和操作,这些就由类来进行访问
9、静态成员
静态成员:使用static关键字修饰的类成员,表示该成员属于类访问
- PHP静态成员有两种
- 静态属性
- 静态方法
- 静态成员是明确用来给类访问的,而不是对象
- 静态成员只是多了一个static关键字修饰,本身也可以被对象访问
- 静态成员同样可以使用不同访问修饰限定符限定,效果一致
示例
1、静态属性:在类中定义属性的时候使用static关键字修饰,访问的时候只能使用类+范围解析操作符+静态属性访问
class Saler{
# 属性
public $money = 0;
public static $count = 0; # 静态属性
}
# 静态成员可以直接使用类访问,而不需要先实例化对象
echo Saler::$count;
2、静态方法:在类中定义方法的时候使用static关键字修饰,访问的时候使用类+范围解析操作符+静态方法名字()访问
class Saler{
# 方法
public static function showClass(){
echo __CLASS__;
}
}
# 类直接访问
Saler::showClass();
3、在类的内部也可以访问静态成员,同样是使用类名+范围解析操作符+静态属性/静态方法()
class Saler{
# 属性
private static $count = 0; # 私有,不允许外部直接访问
# 方法
public static function showClass(){
echo Saler::$count;
}
}
# 类直接访问
Saler::showClass();
4、静态方法本质也是类中定义的方法,因此也可以使用对象进行访问,但是不建议
# 对象访问静态方法
$s = new Saler();
$s->showClass(); # 输出0
5、同理,方法也是在类内部,在编译时就存在,因此可以通过类来进行访问,使用范围解析操作符,但是非常不建议(会报错:因为类只允许访问静态成员和类常量)
class Saler{
public function testStatic(){
echo __FUNCTION__;
}
}
# 类访问普通成员方法
Saler::testStatic(); # 输出testStatic,但是报错,当前访问的不是静态方法
6、静态方法本质是给类访问,所以不允许在静态方法内部使用$this对象
class Saler{
public static function testStaticThis(){
var_dump($this); # 致命错误:$this放到了不该放的位置
}
}
小结
1、为了保障类能直接访问数据和操作数据,可以在属性和方法前增加static关键字变成静态属性和静态方法
2、类通过类名+范围解析操作符+静态成员的方式进行访问
3、静态成员也受访问修饰限定符的限定,访问权限与普通属性和方法的限制一样
4、对象可以无条件访问静态方法,而类只能访问不带$this的普通方法(不建议)
5、静态成员是给类访问的,非静态成员是给对象访问的
- 静态属性和方法(静态和非静态)都是保存在类结构中(代码段)
- 普通属性保存在对象生成的对象空间里(堆)
6、静态成员的访问效率比非静态成员高,因此有种说法是能用静态的时候就不用非静态(对象的特点是多元化,而静态的特点是单一化)
10、self关键字
self关键字:在类的内部(方法里面)使用,代替类名的写法
-
self如同$this代表内部对象一样,能够在方法内部代替当前类名
-
能够保障用户方便修改类名字
-
self关键字是代替类名,所以需要配合范围解析操作符
::
示例:
1、self是用来代替类名的,与范围解析操作符::
一起使用的
class Saler{
# 静态属性
private static $count = 0; # 私有,不允许外部直接访问
# 静态方法
public static function showClass(){
echo Saler::$count;
echo self::$count; # 代替类名
}
}
2、self也可以在类的内部方便实例化对象:比如构造方法被私有化之后,就没有办法在类外部实例化对象,此时可以在类内部进行对象实例化
class Saler{
# 属性
private static $count = 0; # 私有,不允许外部直接访问
private function __construct(){} # 私有,不允许外部实例化(因为对象不能外部调用)
# 方法
public static function getInstance(){
return new Saler(); # 使用类名实例化
return new self(); # 使用self关键字实例化
}
}
$s = Saler::getInstance();
小结
1、self是一种在类内部用来代替类名的关键字
2、self可以用来在类内部访问静态成员
3、self也可以在类内部用来实例化对象
4、帮助类名修改时,不用修改任何类的内部结构
11、对象克隆
克隆对象:clone,即通过已有的对象复制一个新的同样的对象,但是两者之间并非同一个对象
- 克隆对象与原来对象内容一致(表象)
- 克隆出来的对象是新对象
- 对象克隆出来后会自动调用魔术方法__clone()(如果有该方法)
步骤:
1、定义类时考虑对象是否允许被克隆,以及允许克隆后是否需要针对克隆对象做操作
- 不允许克隆:私有化__clone()魔术方法(不允许外部克隆,使用者一般都是外部)
- 允许克隆处理:在__clone()方法中设定好克隆对象的处理
2、实例化对象并保存到变量
3、需要从已有对象产生新对象(不是赋值)
4、使用clone产生对象
示例:
1、对象克隆是通过clone关键字实现,即:clone 对象;
class Saler{
# 属性
public $count;
private $money;
}
# 实例化
$s1 = new Saler();
$s1->count = 1;
# 克隆
$s2 = clone $s1;
2、克隆出来的对象与原来对象是两个内存地址,因此是两个不同的对象
# 接上述代码
$s2->count = 2;
echo $s1->count; # 1,没有变化
3、对象在实例化的时候会自动调用存在的构造方法__construct(),同样的,在类的内部,PHP允许定义一个__clone()的方法,在对象被克隆后,新克隆出来的对象会自动调用
class Saler{
# 属性
public $count;
private $money;
# 克隆方法
public function __clone(){
var_dump($this); # 编号为2,代表是克隆出来的对象
$this->count++;
}
}
# 实例化
$s1 = new Saler();
$s1->count = 1;
# 克隆
$s2 = clone $s1;
4、如果不允许对象被克隆,可以将__clone()方法私有化(本质是不允许对象在外部被克隆)
class Saler{
# 属性
public $count;
private $money;
# 私有化克隆方法
private function __clone(){}
}
# 实例化
$s1 = new Saler();
$s1->count = 1;
# 克隆
$s2 = clone $s1; # 致命错误:不允许对象在外部访问一个私有方法
小结
1、对象可以通过克隆来得到新的对象(以前只有实例化)
2、克隆出来的对象会自动调用类中对应的__clone()方法(如果有)
3、因为克隆对象是新对象,不会改变原来的对象,如果需要一个和当前对象一致状态的对象,但是又不想改变当前对象的状态,那么就可以通过克隆来实现
4、可以通过私有化克隆方法来实现禁止外部对象克隆
15、总结
1、面向对象编程核心是“万物皆对象”的思想,与面向过程编程思想的本质区别是事务操作的主体:每一次操作都是由明确的对象来执行
2、面向对象思想的本质是将数据(属性)、数据操作(函数)进行的一次二次封装(类),而往后的所有操作都必须由类或者类产生的对象进行调用
3、面向对象核心关键字
-
类:class,结构主体,某一类相似主体的公共部分抽离
-
类成员:类结构中能够直接定义的成员
- 属性(property):存储数据的变量
- 方法(method):数据操作的逻辑
- 类常量(const):存储固定数据的内部常量(const定义)
-
实例化:new,类结构产生对象的过程
-
实例:instance,一个具体的对象
4、访问修饰限定符:限定被修饰成员的方位位置(所有类成员都能被访问)
- public:公有,表示不限定访问区域
- protected:受保护,表示限定范围为关联类内部(本质是方法内部,关联类需要学习继承)
- private:私有,表示限定范围为自己类内部(内部方法内)
5、类内部对象:$this
- 普通方法内部,代表来访对象
- 因为在类内部,所以不论任何访问修饰限定符限定,都可以访问
6、魔术方法:自动调用的方法
- 构造方法:__construct(),对象初始化资源,对象实例化后自动调用
- 析构方法:__destruct(),对象销毁资源,销毁时对象自动调用
- 克隆方法:__clone(),对象被克隆后,克隆对象自动调用
7、对象传值:对象是引用传值,不会产生新对象
8、范围解析操作符:::
,用于类直接访问成员的符号
- 类访问类专属成员:类常量(静态属性和静态方法)
- 对象也可以使用该符号访问类成员(不建议)
9、静态成员:使用static关键字修饰的成员,用来给类访问的成员(对象也能访问)
- 静态成员:静态属性和静态方法
- 静态成员在编译(类加载到内存)时初始化,不用产生对象即可访问(效率高)
- 静态属性不会出现在对象的内存空间
10、self关键字:类内部用来代表类名访问类成员的
- self与范围解析操作符结合访问:self::类成员
- self可以代替类名在类内部进行实例化:new self()
11、对象克隆:从已有对象产生新对象
- 防止克隆:私有化话克隆魔术方法
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析