PHP 静态属性和静态方法
1、基本使用
前面介绍的 PHP 类属性和方法都要在类实例化后才能调用(常量属性除外),除此之外,PHP 还提供了静态属性和静态方法,所谓「静态」指的是无需对类进行实例化,就可以直接调用这些属性和方法,这么生讲有点硬,我们举个例子一看就明白了。
静态属性和方法的定义和调用
在 php_learning/oop
目录下新建一个 static.php
文件,编写一段测试代码如下:
<?php
class Car
{
public static $WHEELS = 4;
public static function getWheels()
{
return self::$WHEELS;
}
}
在 PHP 中,我们通过 static
关键字来修饰静态属性和方法,这里我们定义了一个静态属性$WHEELS
和静态方法 getWheels
,由于静态属性和方法可以直接通过类引用,所以又被称作类属性和类方法(相应的,非静态属性和非静态方法需要实例化后通过对象引用,因此被称作对象属性和对象方法),静态属性和方法可以通过 类名::属性/方法
的方式调用:
echo "WHEELS:" . Car::$WHEELS . PHP_EOL;
echo "getWheels:" . Car::getWheels() . PHP_EOL;
如果是在类内部方法中,需要通过 self::
引用当前类的静态属性和方法,就像常量一样,因为静态属性和方法无需实例化类即可使用,而没有实例化的情况下,$this
指针指向的是空对象,所以不能动过它引用静态属性和方法:
同理,我们也不能在静态方法中通过 $this
引用对象属性和方法。
静态属性支持动态修改
为了以示区别,这里通过了大写字母设置静态属性变量名,这不是强制的,因为静态属性名和常量不同,可以在运行时进行修改,只是它的作用域是整个类,而不是某个对象:
Car::$WHEELS = 8;
echo "getWheels:" . Car::getWheels() . PHP_EOL;
上述代码的打印结果是:
getWheels:8
并且静态属性和方法与对象属性和方法一样,支持设置 private
、protected
、public
三种可见性级别。
调用另一个类的静态属性/方法
如果在一个类中调用其他类的静态属性和方法,需要通过 完整类名::
进行引用:
<?php
class Gas
{
public static $POWER = '汽油';
}
class Car
{
protected static $WHEELS = 4;
public static function getWheels()
{
return self::$WHEELS;
}
public static function printCar()
{
printf("这辆车有 %d 个轮子,使用 %s 作为动力来源n", self::$WHEELS, Gas::$POWER);
}
}
Car::printCar();
这里我们通过 Gas::POWER 引用了 Gas 中的静态属性 POWER,静态方法也是类似,上述代码打印结果如下:
在非静态方法中调用静态属性/方法
另外,我们前面提到不能在静态方法中通过 $this
调用非静态属性/方法,但是在非静态方法中可以通过 self::
调用静态属性/方法:
class Car
{
...
public static function printCar()
{
return sprintf("这辆车有 %d 个轮子,使用 %s 作为动力来源n", self::$WHEELS, Gas::$POWER);
}
public function __toString()
{
return self::printCar();
}
}
$car = new Car();
echo $car;
这很好理解,因为前者是因为没有实例化就可以调用,后者实例化后不影响类方法的调用,在上述代码中,我们将静态方法 printCar
调整为通过 sprintf
函数返回格式化字符串,然后在魔术方法 __toString
方法中调用,作为该非静态方法的返回值。上述代码的打印结果是:
完全可以正常运行。
2、进阶功能
静态方法的继承和重写
和非静态属性/方法一样,静态属性和方法也可以被子类继承,静态方法还可以被子类重写:
class Car
{
...
public static function getClassName()
{
return __CLASS__;
}
public static function who()
{
echo self::getClassName() . PHP_EOL;
}
}
class LynkCo01 extends Car
{
public static function getClassName()
{
return __CLASS__;
}
}
通过 __CLASS__
可以获取当前类的类名,我们分别调用两个类的 getClassName
方法:
echo Car::getClassName() . PHP_EOL;
echo LynkCo01::getClassName() . PHP_EOL;
打印结果如下:
说明子类重写了父类的同名静态方法,同样我们在子类上也可以调用父类中的 who
方法:
Car::who();
LynkCo01::who();
上述代码的打印结果是:
Car
Car
咦?为什么第二个打印的结果是父类名 Car
而不是子类名 LynkCo01
?这是因为,和 $this
指针始终指向持有它的引用对象不同,self
指向的是定义时持有它的类而不是调用时的,为了解决这个问题,从 PHP 5.3 开始,新增了一个叫做后期静态绑定的特性。
后期静态绑定
后期静态绑定(Late Static Bindings)针对的是静态方法的调用,使用该特性时不再通过 self::
引用静态方法,而是通过 static::
,如果是在定义它的类中调用,则指向当前类,此时和 self
功能一样,如果是在子类或者其他类中调用,则指向调用该方法所在的类,我们通过后期静态绑定改写上述代码:
class Car
{
...
public static function getClassName()
{
return __CLASS__;
}
public static function who()
{
echo static::getClassName() . PHP_EOL;
}
}
class LynkCo01 extends Car
{
public static function getClassName()
{
return __CLASS__;
}
}
...
Car::who();
LynkCo01::who();
再次执行,打印结果如下:
Car
LynkCo01
表明后期静态绑定生效,即 static
指向的是调用它的方法所在的类,而不是定义时,所以称之为后期静态绑定。
此外,还可以通过 static::class
来指向当前调用类的类名,例如我们可以通过它来替代 __CLASS__
,这样上述子类就没有必要重写 getClassName
方法了:
class Car
{
...
public static function getClassName()
{
return static::class;
}
public static function who()
{
echo static::getClassName() . PHP_EOL;
}
}
class LynkCo01 extends Car
{
}
代码执行结果和之前一样。
同理,self::class
则始终指向的是定义它的类,感兴趣的同学可以自行测试,这里不再演示了。self
和 static
各有其使用场景,后面我们会看到其实际的使用场景。
关于 PHP 静态属性和方法的使用就简单介绍到这里,明天,学院君将给大家介绍下 PHP 类中常见的魔术方法。
(全文完)
- 楼盘价格数据采集与可视化分析
- Android LayoutInflater原理分析,带你一步步深入了解View(一)
- 深入理解Linux磁盘的奥秘
- Linux文件系统——全方位掌握
- TensorFlow和深度学习入门教程
- php+mysql实现分页代码
- 主成分分析降维(MNIST数据集)
- Android 使用dagger2进行依赖注入(基础篇)
- Html小知识总结
- 如何训练一个性能不错的深度神经网络
- 使用AndroidStudio编译NDK的方法及错误解决方案
- 计算机视觉 | Python OpenCV 3 使用背景减除进行目标检测
- linux(centos)搭建SVN服务器
- 简单的Hibernate入门简介
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- thinkPHP5框架路由常用知识点汇总
- PHP实现一个限制实例化次数的类示例
- AndroidStudio中重载方法@Override的使用详解
- mysqli扩展无法在PHP7下升级问题的解决
- PHP通过文件保存和更新信息的方法分析
- PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
- PHP创建XML的方法示例【基于DOMDocument类及SimpleXMLElement类】
- android之json数据过长打印不全问题的解决
- PHP实现时间日期友好显示实现代码
- AndroidStudio插件GsonFormat之Json快速转换JavaBean教程
- android studio错误: 常量字符串过长的解决方式
- Android Shader着色器/渲染器的用法解析
- PHP实现的文件浏览器功能简单示例
- Laravel中正确地返回HTTP状态码方法示例
- Android 实现抖音头像底部弹框效果的实例代码