初学 PHP 类的自动加载

一.几点要求

在实际项目中,每个功能会被定义成一个类,并且每个类都会被放到单独的一个PHP文件中,在另外一个文件中想要使用某一个类,就需要引入存放该类的类文件.
类文件的定义有几个要求:

  • 类文件名以 .class.php 结尾.
  • 类文件名要与其中的类名一致.
  • 类文件以及类的命名使用"大驼峰"命名法.
  • 类中方法与属性使用"小驼峰"命名法.

二.手动加载类

./User.class.php 类文件.

<?php

class User {
    private $name = "刘看山";
    private $age  = "4";

    public function getInfo(){
        return "我是{$this->name},我有{$this->age}岁了!";
    }
}

./index.php 文件.

<?php
require_once "./User.class.php";

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"

在上面这个例子中, ./index.php 文件中的 require_once "./User.class.php"; 这个语句相当于把 ./User.class.php 类文件中的代码赋值到了 ./index.php 文件中,但是当真正做项目的时候,类文件成百上千,不可能每一次都这样手动来加载.

三.自动加载类

__autoload() 函数

注意,该函数在PHP 7.2.0中被废弃了.
当在脚本中调用本脚本中不存在的类时, __autoload() 函数会被调用,有如下几种情况:

  • new一个对象时.例如 $obj = new User();
  • 调用类中的静态属性或者静态方法时.例如 $result = User::showMessage()
  • 继承父类时.例如 class Staff extends Person{};
  • 实现接口时.这个还没学过.

在该函数中要做两件事情:

  • 拼装一个类文件的真实物理路径.
  • 类文件存在则包含之.

上文中的 ./User.class.php 类文件保持不变.修改 ./index.php 文件.

<?php
function __autoload($className) {
    //构建类文件的真实路径
    $filePath = "./$className.class.php";
    //如果类文件存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"

spl_autoload_register() 函数

使用该函数需要传入一个回调函数,这里结合了回调函数的知识点.上文中的 ./User.class.php 类文件保持不变.修改 ./index.php 文件.有三种写法,如下所示.

<?php
spl_autoload_register(function ($className) {
    //构建类文件的真实路径
    $filePath = "./$className.class.php";
    //如果类文件存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
});

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"

或者写成

<?php
$myFunc = function ($className) {
    //构建类文件的真实路径
    $filePath = "./$className.class.php";
    //如果类文件存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
};//这里有个坑,要注意记得加上分号

spl_autoload_register($myFunc);

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"

或者写成

<?php
function myFunc($className) {
    //构建类文件的真实路径
    $filePath = "./$className.class.php";
    //如果类文件存在,包含之
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

spl_autoload_register("myFunc");

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"

相比较于 __autoload() 函数, spl_autoload_register() 函数的优势是可以注册多个回调函数,每个回调函数可以对应不同的加载规则.下面做个记录.
./User/User.class.php 文件.

<?php

class User {
    private $name = "刘看山";
    private $age  = "4";

    public function getInfo(){
        return "我是{$this->name},我有{$this->age}岁了!";
    }
}

./Student/Student.class.php 文件.

<?php

class Student {
    private $name = "刘看火";
    private $job  = "打妖怪";

    public function getInfo(){
        return "我是{$this->name},我的工作是{$this->job}";
    }
}

./Teacher/Teacher.class.php 文件.

<?php

class Teacher {
    private $name = "刘看水";
    private $school  = "北京大学";

    public function getInfo(){
        return "我是{$this->name},我在{$this->school}任教";
    }
}

./index.php 文件.

<?php
function myFunc1($className) {
    $filePath = "./User/$className.class.php";
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

function myFunc2($className) {
    $filePath = "./Student/$className.class.php";
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

function myFunc3($className) {
    $filePath = "./Teacher/$className.class.php";
    if (file_exists($filePath)) {
        require_once "./$filePath";
    }
}

spl_autoload_register("myFunc1");
spl_autoload_register("myFunc2");
spl_autoload_register("myFunc3");

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"
$studentObj = new Student();
echo $studentObj->getInfo();//输出"我是刘看火,我的工作是打妖怪"
$teacherObj = new Teacher();
echo $teacherObj->getInfo();//输出"我是刘看水,我在北京大学任教"

上面这种写法很繁琐,优化一下.
./User/User.class.php , ./Student/Student.class.php , ./Teacher/Teacher.class.php 这三个文件保持不变.修改 ./index.php 文件.

<?php
spl_autoload_register(function ($className) {
    $filePaths = [
        "./User/$className.class.php",
        "./Student/$className.class.php",
        "./Teacher/$className.class.php",
    ];
    foreach ($filePaths as $filePath){
        if (file_exists($filePath)){
            require_once "$filePath";
        }
    }
});

$userObj = new User();
echo $userObj->getInfo();//输出"我是刘看山,我有4岁了!"
$userObj = new Student();
echo $userObj->getInfo();//输出"我是刘看火,我的工作是打妖怪"
$userObj = new Teacher();
echo $userObj->getInfo();//输出"我是刘看水,我在北京大学任教"
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!