swoole4.0之打造自己的web开发框架(1)

原创
2018/12/20 12:59
阅读数 338

本系列将通过一系列文章打造一个简单的开发框架,以便帮助大家理解:

  1. 和fpm模式下有何区别?

  2. 如何整合现有的开发框架

 

swoole4.0协程初探这篇文章中,我们已经有了一个http server的雏形了,但就一个单一的文件,代码耦合在一起,下面我们开始改造之旅了

 

框架先起个名吧?

我们的公众号是php饭米粒,是由phpfamily谐音过来的,那框架就叫:Family 了

 

规划目录结构

为什么要先规划目录结构,整体前期我们先通过 约定大于配置的 的方式来组织的我们的代码,这样方便大家的统一理解, 另一个重要的约定就是:符合PSR规范

.
├── application         //应用目录
│   ├── config          //配置文件
│   ├── controller      //controller
│   └── index.php       //统一入口
├── bin
│   └── family.service  //服务管理脚本,类php-fpm.service
└── framework           //框架约定目录
    └── Family          //框架主目录
            └── family.php      //框架主文件

这是一个雏形了,我们将在这个基础上一步一步打造自己的框架, 

 

 

统一入口

接下来我们要定义一个方法,做为程序的入口,让程序能够跑起来,这里我们只支持 http server,所以代码如下:
 

<?php
//path framework/Family/Family.php
namespace Family;

use Family\Core\Config;
use Swoole;


class Family
{
    final public static function run()
    {
        $http = new Swoole\Http\Server('0.0.0.0', 9501);
        $http->set([
            "worker_num" => 1,
        ]);
        $http->on('request', function ($request, $response) {
            $response->end("hello, family is run");
        });
        $http->start();
    }
}

 

然后我们在application/index.php加入代码:

<?php
use Family\Family;

require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR . 'Family' . DIRECTORY_SEPARATOR . 'Family.php';
Family::run();

 

执行 php application/index.php, 浏览器执行:http://127.0.0.1:9501,输出如下

 

 

但以这里,我们啥也做不了,和单一的文件基本没什么区别,接下我们做三件事:

  1. 实现一个类的自动加载

  2. 把配置参数抽离出来

  3. 实现一个简单的路由

 

 

自动加载

我们这里先不用composer,自己实现一个简单的自动加载功能, 在Family类添加一个方法:

/**
 * @param $class
 * @desc 自动加载类
 */
final public static function autoLoader($class)
{
    //定义rootPath
    $rootPath = dirname(dirname(__DIR__));

    //把类转为目录,eg \a\b\c => /a/b/c.php
    $classPath = \str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';

    //约定框架类都在framework目录下, 业务类都在application下
    $findPath = [
        $rootPath . DIRECTORY_SEPARATOR . 'framework' . DIRECTORY_SEPARATOR,
        $rootPath . DIRECTORY_SEPARATOR . 'application' . DIRECTORY_SEPARATOR,
    ];

    //遍历目录,查找文件
    foreach ($findPath as $path) {
        //如果找到文件,则require进来
        $realPath = $path . $classPath;
        if (is_file($realPath)) {
            require "{$realPath}";
            return;
        }
    }

}

 

实现一个配置加载和读取类

在框架创建一个Core目录,此目录是框架的一些核心类, 第一个核心类就是Config.php

<?php
namespace Family\Core;

class Config
{

    /**
     * @var 配置map
     */
    public static $configMap;

    /**
     * @desc 读取配置,默认是application/config/default.php
     */
    public static function load()
    {
        $configPath = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'application' . DIRECTORY_SEPARATOR . 'config';
        self::$configMap = require $configPath . DIRECTORY_SEPARATOR . 'default.php';
    }

    /**
     * @param $key
     * @desc 读取配置
     * @return string|null
     *
     */
    public static function get($key)
    {
        if(isset(self::$configMap[$key])) {
            return self::$configMap[$key];
        }

        return null;
    }
}

 

然后我们就可以把配置抽离出来:
 

<?php
//file: application/config/default.php
return [
    'host' => '0.0.0.0',
    'port' => 9501,
    'worker_num' => 1
];


现在run方法就变成了:

final public static function run()
{
    //先注册自动加载
    \spl_autoload_register(__CLASS__ . '::autoLoader');
    //加载配置
    Config::load();

    //通过读取配置获得ip、端口等
    $http = new Swoole\Http\Server(Config::get('host'), Config::get('port'));
    $http->set([
        "worker_num" => Config::get('worker_num'),
    ]);
    $http->on('request', function ($request, $response) {
        $response->end("hello, family is run");
    });
    $http->start();
}

 

实现一个简单的路由

这里我们还是通过约定大于配置的方式,规定url的组成方式是:
http://127.0.0.1:9501/controller/method ,那代码如下:
 

<?php
namespace Family\Core;


class Route
{
    public static function dispatch($path)
    {
        //默认访问 controller/index.php 的 index方法
        if (empty($path) || '/' == $path) {
            $controller = 'Index';
            $method = 'Index';
        } else {
            $maps = explode('/', $path);
            $controller = $maps[1];
            $method = $maps[2];
        }

        $controllerClass = "controller\\{$controller}";
        $class = new $controllerClass;

        return $class->$method();

    }
}

 

接下来我们在controller目录下新建一个Index.php, 代码如下:
 

<?php
namespace controller;

class Index
{
    public function index()
    {
        return 'i am family by route';
    }

    public function tong()
    {
        return 'i am tong ge';
    }
}

接下来,我们把run方法改造下
 

final public static function run()
{
    //先注册自动加载
    \spl_autoload_register(__CLASS__ . '::autoLoader');
    //加载配置
    Config::load();

    //通过读取配置获得ip、端口等
    $http = new Swoole\Http\Server(Config::get('host'), Config::get('port'));
    $http->set([
        "worker_num" => Config::get('worker_num'),
    ]);
    $http->on('request', function ($request, $response) {
        //自动路由
        $result = Route::dispatch($request->server['path_info']);
        $response->end($result);
    });
    $http->start();
}

 

执行 php application/index.php,

浏览器输入 http://127.0.0.1:9501/Index/tong 

可输出:  i am tong ge

 

现在我们的代码结构如下:

.
├── application             //应用目录
│   ├── config              //配置目录
│   │   └── default.php     //默认配置文件
│   ├── controller          //controller目录
│   │   └── Index.php       //controller文件
│   └── index.php           //统一入口
├── bin                     
│   └── family.service      //预留的服务管理脚本,类php-fpm.service
└── framework               //框架目录
    └── Family              //框架主目录
        ├── Core            //框架核心类目录
        │   ├── Config.php  //配置读取
        │   └── Route.php   //路由管理
        └── Family.php      //框架主文件

至此已经实现了一个基础的web框架了

 

下一篇,将实现各种的异常处理和日志处理

 

github地址: https://github.com/shenzhe/family

--------------伟大的分割线----------------

PHP饭米粒(phpfamily) 由一群靠谱的人建立,愿为PHPer带来一些值得细细品味的精神食粮!

饭米粒只发原创或授权发表的文章,不转载网上的文章

所发的文章,均可找到原作者进行沟通。

也希望各位多多打赏(算作稿费给文章作者),更希望大家多多投搞。

投稿请联系:

shenzhe163@gmail.com

 

本文由 半桶水 授权 饭米粒 发布,转载请注明本来源信息和以下的二维码(长按可识别二维码关注)

展开阅读全文
加载中

作者的其它热门文章

打赏
0
1 收藏
分享
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部