批改状态:合格
老师批语:
静态成员、类常量是属于类本身,不需要实例化就可以被访问到,直接使用类名访问,减少实例化对象所占内存。
static 标识静态成员(默认为 public,可以不写)
const 类常量(不能用 define ),通常在类内部使用,不建议在类外部使用
在类内部,使用 self::访问静态成员(需要加$)、类常量(不需要加$),(不能使用 $this)
__callStatic 当调用不存在或者没有权限访问的静态方法时,此魔术方法会被调用
:: 范围解析符 self::用于类常量 静态成员的访问
class Teacher{// 类常量public const CATES = ['前端', '后端', '全栈'];// 静态属性public static $uname;private static $salary;// 不加访问控制,默认为 publicstatic $siteName = 'php中文网';static $count = 0;// 构造方法,创建对象时初始化属性public function __construct($uname, $salary){//静态成员与类的实例无关 不能使用$this来访问 使用self::访问静态成员 类常量self::$salary = $salary;self::$uname = $uname;self::$count++;}static function getBK(){// 非静态成员是对象级别的存在,静态成员是类级别的存在,随着类的加载而加载,优先于对象存在的,在静态方法中无法访问非静态成员(此时还不存在对象)return self::$uname . '来自' . self::$siteName . '可以胜任' . join(',', self::CATES) . '的相关课程';}}$mj = new Teacher('灭绝师妹', 2000);echo Teacher::$uname; // 灭绝师妹// 可以使用对象来访问,但不建议echo $mj::$uname; // 灭绝师妹$mj1 = new Teacher('灭绝老师', 5000);// 实例化对象会改变静态属性的值,值为最后一次实例化的值,也会改变之前实例化的对象echo Teacher::$uname; // 灭绝老师echo $mj::$uname; // 灭绝老师//类常量不建议在类外访问print_r(Teacher::CATES); // Array ( [0] => 前端 [1] => 后端 [2] => 全栈 )// 访问静态方法echo Teacher::getBK(); // 灭绝老师来自php中文网可以胜任前端,后端,全栈的相关课程// 访问次数echo Teacher::$count; // 2
接口(interface)是定义,类(class)是实现。
// 接口(interface)interface iDemo{// 所有成员必须是公开的(public)public const gender = 'MALE';// 接口(interface)所有方法都是抽象方法 只有声明 没有实现public function sum($a, $b);public function sub($a, $b);public function mul($a, $b);public function div($a, $b);}interface test{public const T = 20;}// 抽象类(abstract):// 抽象类 可以存在 抽象方法和工作方法 不能被实例化// 抽象类可以继承多个接口// 实现部分方法,剩余方法由类(class)完成abstract class aDemo implements iDemo, test{// 重写接口 iDemo 中的 sum 方法public function sum($a, $b){return $a + $b;}// 重写接口 iDemo 中的 sub 方法public function sub($a, $b){return $a - $b;}}// 类只能继承一个父类(抽象类)// 类(class):实现全部方法,可以实例化class Work extends aDemo{// 重写接口 iDemo 中的 mul 方法public function mul($a, $b){// 调用接口 test 中的常量 Techo self::T;return $a * $b;}// 重写接口 iDemo 中的 div 方法public function div($a, $b){return $a / $b;}}$obj = new Work;$obj->mul(5,6); // 20 ( echo self::T; )echo $obj->sum(10, 20); // 30
trait是基于类的语法,但是和接口一样,不能被实例化 ,是对类功能的横向扩展。
php oop 默认是单继承 只能继承一个父类->高耦合
// 接上例的接口和抽象类// 定义 trait,扩展类的功能// 断点打印 t1trait t1{public function dd($data){var_dump($data);die;}}// 扩展 sum() 功能trait t2{public function sum($a, $b, ...$args){return $a + $b + array_sum($args);}}class Work extends aDemo{// 同名方法优先级 类同名方法(重写)>trait>继承成员方法//trait 功能组合式地实现多继承use t1, t2;// 重写接口 iDemo 中的 mul 方法public function mul($a, $b){// 调用接口 test 中的常量 Techo self::T;return $a * $b;}// 重写接口 iDemo 中的 div 方法public function div($a, $b){return $a / $b;}// 类同名方法(重写),优先级最大// public function sum($a, $b)// {// return 'hello';// }}echo $obj->sum(10, 20, 30, 40, 200); // 300 (trait t2)$obj->dd('你好'); // 你好(trait t1)
self:: 对当前类的静态引用是由限制的,self::取决于定义当前方法所在的类, 定义类与调用类(实例化的对象)不能动态绑定
class Car{// 私有静态方法 getName()private static function getName(): string{return 'car';}public static function run(){// self:: 指向当前类,实例化的对象中依然指向当前类 Carreturn self::getName();}}class Benz extends Car{// 重写父类的静态方法 getName()public static function getName(){return 'E300';}}echo Car::run(); // car// 调用类中 self::还是指向父类 Car,而不是指向调用类 Benzecho Benz::run(); // car
使用后期静态绑定 static::,不再被解析为定义当前方法所在的类,而是在调用类。
class Car{private static function getName(): string{return 'car';}public static function run(){// self:: 改为 static::return static::getName();}}class Benz extends Car{public static function getName(){return 'E300';}}echo Car::run(); // car// 后期静态绑定 static::,不再指向父类 Car,而是指向调用类 Benzecho Benz::run(); // E300
全局成员: 常量、命名函数、类(接口),不受作用域限制,重名的话会冲突
命名空间:可以解决全局成员命名冲突的问题
namespace ns1;class test{public static function show(){// __FUNCTION__ 只是返回方法(或者函数)的名字// __METHOD__ 返回类名和方法的名字(包括命名空间,如有)return __METHOD__;}}namespace ns2;class test{public static function show(){return __METHOD__;}}// 当前在命名空间 ns2,可以直接调用本空间下的类echo test::show(); // ns2\test::show// call_user_func() 回调,是异步,脱离了当前线程,不能直接调用,需要加上命名空间echo call_user_func(['test', 'show']); // 报错找不到test类echo call_user_func(['ns2\test', 'show']); // ns2\test::show// 从非全局命名空间(当前为 ns2)访问别的空间中的类 先回到root: \// 注意:这里的反斜杠(\)是空间分隔符,不是目录分隔符echo \ns1\test::show(); // ns1\test::show
命名空间下的函数,优先级高于系统同名函数 (系统函数默认在全局命名空间)
namespace demo;function var_dump($data){echo 'var_dump' . $data;}var_dump('你好'); // var_dump你好
目录结构:
app\controller 下面的两个类(命名空间设置为类所在的目录)
Index.php
namespace app\controller;class Index{static function index(){return __METHOD__ . "<br />";}}
Login.php
namespace app\controller;class Login{static function index(){return __METHOD__ . "<br />";}}
autoload.php:类的自动加载器
spl_autoload_register(function ($className) {// 自动加载器引入的类名 $className 是带有命名空间的(app\controller\Index)// 命名空间名称与目录树对应,可以参与类文件所在位置的拼接// 命名空间的反斜杠(\)是空间分隔符,不是目录分隔符,需要转换为目录分割符// "\\":第一个 \ 是转义符,第二个 \ 是空间分隔符$file = str_replace("\\", DIRECTORY_SEPARATOR, $className) . '.php';if (is_file($file) && file_exists($file)) require $file;});
index.php:入口文件,使用 use 引入其他命名空间中的类
// 入口文件// 注意:入口文件不能放在类所在的目录,否则无法引入require __DIR__ . DIRECTORY_SEPARATOR . 'autoload.php';// 1. 直接调用其他命名空间中的类,需加上命名空间// 无需 use app\controller;// 当前为全局命名空间,无需加 root:\echo app\controller\Index::index(); // app\controller\Index::index// 如果需要给命名空间起别名,则需要 use asuse app\controller as ac;echo ac\login::index(); // app\controller\Login::index// 2. use 引入其他命名空间中的类,然后可以直接调用改类use app\controller\Index;use app\controller\Login;echo Index::index(); // app\controller\Index::indexecho Login::index(); // app\controller\Login::index// 给引入的类起别名: use as// 不起别名,默认为Indexuse app\controller\Index as in;echo in::index(); // app\controller\Index::index
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号