1.类声明
class 类名
{
//类体
}
2.继承
一个类可以在类声明中使用 extends
关键字继承另一个类的属性、常量和方法。
一个类不支持继承多个父类,只能继承一个父类。
class 子类 extends 父类
{
//类体
}
3.构造函数和析构函数
3.1构造函数声明
function __construct(参数)
{
//构造函数体
}
具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
如果子类没有定义构造函数,则会从父类继承(前提是父类构造函数没有被定义为 private
的话)。
如果子类中定义了构造函数,则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()
。
一个类可以没有构造函数,构造函数可以没有参数,构造函数体可以是空的。
3.2构造函数提升(Promotion)
构造函数就像普通函数一样,也支持访问控制修饰符(visibility modifier)。
当构造函数参数带访问控制修饰符时,PHP 会同时把它当作构造函数参数和类属性, 并将参数值赋值给类属性。 构造函数体可以是空的,或者包含其它语句。 参数值赋值到对应类属性后执行构造函数体中额外的代码语句。
//构造函数体内将构造函数的参数赋值给类属性
class Point
{
protected int $x;
protected int $y;
public function __construct(int $x, int $y = 0)
{
$this->x = $x;
$this->y = $y;
}
}
//构造函数属性提升简写方式
class Point
{
public function __construct(protected int $x, protected int $y = 0)
{
}
}
3.3析构函数
function __destruct()
{
//析构函数体
}
当某个对象没有被任何引用或者显式调用析构函数时,析构函数才会被调用。
如果子类没有定义析构函数,则会从父类继承(前提是父类析构函数没有被定义为 private
的话)。
如果子类中定义了析构函数,则不会隐式调用其父类的析构函数。要执行父类的析构函数,需要在子类的析构函数中调用 parent::__destruct()
。
4.创建对象
//构造函数有参数需要传递
$变量 = new 类名(参数1, 参数N);
//没有构造函数 或 构造函数的参数非必选参数,则类名后的括号可省略。
$变量 = new 类名();
5.访问成员
可以用 ::
(范围解析运算符,或称双冒号)来访问静态成员,类常量,还可以用于覆盖类中的属性和方法。
//访问类属性和方法
类名::$类属性;
类名::类方法();
类名::类常量;
可以用 ->
(对象运算符)来访问实例属性和方法。
//访问实例属性和方法
$对象名->实例属性;
$对象名->实例方法();
6.抽象类和抽象方法
abstract class 类名
{
abstract function 方法名称(): 返回类型;
abstract function 方法名称(参数): 返回类型;
function 方法名称(参数): 返回类型
{
//具体实现
}
}
如果一个类里面声明了至少一个抽象方法,那么这个类就必须声明为抽象类。抽象类可以声明有具体实现的方法。
抽象方法体内不能声明具体实现。
当子类从抽象类继承时,子类必须实现定义在父类中的所有抽象方法。
抽象类不能被实例化。
7.匿名(Anonymous)类
匿名类支持 传递参数给匿名类的构造函数、继承其它类、实现接口、导入trait。
//显示声明类
class Logger
{
public function log($msg)
{
echo $msg;
}
}
$util->setLogger(new Logger());
//匿名类
$util->setLogger(new class {
public function log($msg)
{
echo $msg;
}
});
8.覆盖(Override)
子类会继承父类的属性、常量和方法,父类中被继承的属性、常量和方法可以通过在子类中使用同样的名字重新声明来覆盖。但是如果父类中定义的常量或方法时使用了 final
关键字,则该常量或方法不可以被覆盖。可以通过 parent::
来访问父类中被覆盖的方法或静态属性。
8.1方法覆盖
当子类覆盖父类的方法时,子类方法的签名必须兼容父类方法。这就是著名的里氏替换原则(Liskov Substitution Principle,简称 LSP
)。具体签名兼容规则是指:
- 父类方法与子类方法之间遵守协变与逆变规则。
- 父类方法的必选参数,在子类可以改为默认值参数。
- 子类的新增参数可以为默认值参数。
不过 构造函数 和 私有(private
)方法不需要遵循签名兼容规则。
9.重载(Overloading)
PHP中的重载
与其它绝大多数面向对象语言不同。传统的重载
是在类中提供多个同名的方法,但各方法的参数类型和个数不同来实现重新加载具体哪个方法的。而PHP的重载为:当调用当前作用域下未声明或不可见的属性或方法时,对应行为的重载方法(通过魔术方法实现的)会被调用。
所有的重载方法都必须被声明为 public
,不可以被声明为 static
。
9.1属性重载
属性重载方法值可以在对象上下文(->
)工作,在静态上下文(::
)这些魔术方法不会被触发。
属性重载方法 | 描述 |
__set() | 当赋值给 未声明或不可见(protected 或 private)的属性时,__set() 会被调用。 |
__get() | 当读取 未声明或不可见(protected 或 private)的属性的值时,__get() 会被调用。 |
__isset() | 当在 未声明或不可见(protected 或 private)的属性上调用 isset() 或 empty() 函数时,__isset() 会被调用。 |
__unset() | 当在 未声明或不可见(protected 或 private)的属性上调用 unset() 函数时,__unset() 会被调用。 |
9.2方法重载
方法重载方法 | 描述 |
__call() | 在对象上下文,当调用一个不可见的方法时,__call() 会被调用。 |
__callStatic() | 在静态上下文,当调用一个不可见的方法时,__callStatic() 会被调用。 |
10.::class
使用 ::class
可以获取类的完全限定名称。
//用在类上面
<?php
namespace NS
{
class ClassName
{
}
echo ClassName::class;
}
?>
//输出
NS\ClassName
//用在对象上面
<?php
namespace NS
{
class ClassName
{
}
}
$c = new ClassName();
print $c::class;
?>
//输出
NS\ClassName
11.final类
final
关键字加在类前面可以防止父类被子类继承。
final class A
{
//类体
}
12.readonly类
声明为 readonly
的类意味着类里面的所有属性均为 readonly
属性,除了未声明类型的属性和静态属性。
readonly class 类名
{
//类体
}
13.self、parent、static、$this类型
类型 | 描述 |
self | 指向当前类 |
parent | 指向当前类的父类 |
static | 作为返回类型,指向当前类 |
$this | 指向当前实例 |
原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/php/phplang/3457.html