PHP 手写MVC(二) —— 自动加载和Bootstrap

类自动加载:

在使用类的时候会用 requireinclude 将类加载进来,但是每次都手动加载,会导致一系列问题,比如类重复加载,管理困难等。所以解决上述问题,我们使用单独的一个文件来完成所有类的自动加载。

spl_autoload_register()

该函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。

尽管 __autoload() 函数也能自动加载类和接口,但更建议使用 spl_autoload_register() 函数。 spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载(同一个应用中,可以支持任意数量的加载器,比如第三方库中的)。因此,不再建议使用 __autoload() 函数,在以后的版本中它可能被弃用。

core 目录下创建一个 Autoload.php 文件

$ cd tinyphp/core
$ touch Autoload.php

编辑 Autoload.php


// 命名空间和文件目录映射
<?php
$path = [
    'core' => 'core',
    'app' => 'app',
    'controller' => 'app/controllers',
    'model' => 'app/models',
    'view' => 'app/views',
    'dispatcher' => 'core/dispatcher',
];

/**
 * 参数 $class 表示自动加载的类名
 * 
 * 匿名函数中使用 use 可以使用外部变量
 */
spl_autoload_register(function($class) use ($path) {

    //解析类名,如果使用了命名空间,则会查找 $path 中对于的路径【这个地方强烈建议打印一下,自动加载就很清晰了】
    $position = strripos($class,'\\');

    $key = substr($class,0,$position);
    $value = $path[$key] ?? '';

    $file = substr($class,$position+1).'.php';

    require APP_PATH.'/'.$value.'/'.$file;
});

spl_autoload_register() 主要实现类自动加载,参数使用的是匿名函数,通过关键字 use 可以使用外部变量 $path,其作用是提供命名空间和路径的对应关系,例如使用 namespace controller,对应的类在路径 app/controllers

使用方式为,在入口文件public/index.php 中,直接 require 该文件即可。

<?php

define('APP_PATH',dirname(__DIR__));

require APP_PATH.'/core/Autoload.php';

然后我们在core 文件夹下创建一个名为 Application.php 并编辑内容

<?php

namespace core;

class Application
{
    public function run()
    {
        echo 'hello world';
    }
}

自动加载完成,待会启动框架(下文)之后就可以看到效果了。

注册启动项

有时候需要在框架启动时,额外加载一些应用配置或用户定义的方法,比如定义常量,加载自定义辅助函数等(像 Laravel 框架也会去加载 bootstrap 文件进行启动程序引导)。

我们在应用目录 app 中创建一个启动脚本 Bootstrap.php,规定该脚本内所有以 init 的方法都会被调用,并在 Application 类的构造函数中调用该脚本

创建 app/Bootstrap.php,编辑内容

<?php 

namespace app;

class Bootstrap
{
    /**
     * 所有以 init 开始的函数都会被依次调用
     *
     */
    public function initConst()
    {
        echo 'Bootstrap : 1'.PHP_EOL;
    }
    
    public function initHelper()
    {
        echo 'Bootstrap : 2'.PHP_EOL;
    }
}

Application 类中添加启动项

  • 在构造函数 __construct() 中获取 Bootstrap 实例。
  • run() 方法中遍历 Bootstrap 类中以 init 开头的方法并执行。
<?php
//这里用...省略之前的代码,在实际操作中,需要完整的代码,不然会报错
...
    public $boot;
    
    public function __construct()
    {
        /**
         * \app\为命名空间,
         * 第一个\表示在根目录,否在表示在当前命名空间下的子目录
         * 
         * 例如,app\Bootstrap() 表示在类在 tinyphp/core/app 目录下
         * \app\Bootstrap() 则表示在 tinyphp/app 目录下
         */
        $this->boot = new \app\Bootstrap();
    }
    public function run()
    {
        /**
         * 执行启动项
         * 所有init开头的方法都会被调用
         *
         */
        foreach(get_class_methods($this->boot) as $func) {
            if (0 === strpos($func, 'init')) {
                call_user_func([$this->boot,$func]);
            }
        }
    }
...

启动框架

在入口文件 index.php 中启动框架,并执行 run() 方法

<?php

use \core\Application; # 这里就是引入命名空间的起始地方

define('APP_PATH',dirname(__DIR__));

require APP_PATH.'/core/Autoload.php';

(new Application())->run();

进入 public 目录,两种方式执行 php

  • 命令行
$ php index.php
Bootstrap : 1
Bootstrap : 2
  • 使用 PHP 内置服务器
$ php -S localhost:8080

在浏览器输入 http://localhost:8080 , 结果如下

Bootstrap : 1Bootstrap : 2

从结果可以看出,Application 类在实例化的时候执行构造函数,构造函数中完成了启动项的方法调用。

三、总结

本节实现了一个简单的类自动加载和框架的核心类,在启动时加载用户启动项,在 app/Bootstrap.php 中所有以 init 开头的方法都会被依次调用。

下期见

青年 ---------------

735 声望
186 粉丝
0 条评论
推荐阅读
PHP手写MVC (五)—— 路由
路由是一个框架中必不可少的组件,其作用是把 URL 按照预定规则解析到特定控制器中。 我们在这里定义了两种路由规则: 查询字符串。在路径后面使用问号加参数,多个参数用 &amp; 分隔。在配置文件使用 querystrin...

entner4阅读 3.3k

PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go11阅读 2.7k评论 4

封面图
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go6阅读 2.9k评论 4

封面图
图片防盗链破解 解决图片防盗链问题 反向代理
当客户端(浏览器)向服务器请求内容的时候,会提交一个header,这个header中包含了如:浏览器信息、cookie等内容,那么有一个叫referer的东东,也包含在这里面。

TANKING7阅读 11.7k评论 5

Hyperf 3.0 发布,PHP 新时代
在过去的一年半时间里,Hyperf 2.2 共发布了 35 个小版本,使 Hyperf 达到了一个前所未有的高度,这里也获得了一些不错的数据反馈。

huangzhhui4阅读 1.5k评论 1

封面图
微信公众号开发:自动回复文本/图片/图文消息/关键词回复/上传素材/自定义菜单
对接流程1、申请微信公众号测试账号URL:[链接]2、登录,配置开发者服务器URL和Token开发者服务器配置代码:config.php {代码...} URL是config.php在你服务器的URLToken是上面代码自己设置的Token搞定之后,就能完...

TANKING2阅读 10.5k

Ajax实现搜索联想 搜索关键词提醒 无刷新搜索
通过javascript监听搜索框的内容,调用后端即可。(1)javascript监听搜索框的内容(2)把搜索框的关键词传给后端进行搜索(3)搜索到结果,遍历到页面

TANKING1阅读 4.6k

青年 ---------------

735 声望
186 粉丝
宣传栏