V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zoule
V2EX  ›  PHP

在 swoole 中制作一款仿制 laravel 的框架

  •  
  •   zoule · 50 天前 · 1279 次点击
    这是一个创建于 50 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在 swoole 中制作一款仿制 laravel 的框架 首先需要确定一下思路:我希望基于 swoole 的扩展开发的代码在 run 起来的时候,在接收到 ws 或是 tcp 等消息时,自动路由到某个类上,同时类可以实现加载类的依赖注入功能。目前市面上占据主流的一款框架 Laravel,其中有一个依赖注入的功能非常的便捷。一般在通常的框架中拉取 Class 是这样做的:

    class a {
        public $bClassInstance;
        public function __construct(Class b) {
            $classInstance = new b();
        }
        public function doSth() {
            return $this->bClassInstance->xxx();
        }
    }
    
    $b = new b();
    $a = new a($b)
    $a->doSth();
    

    而在 Laravel 中则可以省略一些实例化的步骤, 直接通过类型约束的语法在方法的形参上指定某类的命名空间就自动实例化该类进来了。

    class a {
        public function doSth(b $b) {
            return $b->xxx();
        }
    }
    

    想要实现这一点,必须要了解 php 的反射机制。反射是一个比较冷门的类,他可以做到:使用 namespace 实例化一个类、调用类的方法等,利用这一点,可以构造一个自动装箱的类。

    <?php
    /***
     *  依赖注入容器,若要执行依赖注入,请确保类包含构造函数!
     */
    namespace App\Server;
    
    class Container
    {
        public $config;
        public $reflection;
        public function __construct($namespace)
        {
            try
            {
                $this->reflection = new \ReflectionClass($namespace);
            }
            catch (Exception $e)
            {
                echo $namespace;
            }
        }
        public function builderController($fn, $server, $frame, $userMessage)
        {
            //从 route 中得到的 control 名称
            $this->reflection->getMethod($fn)->invoke($this->autoBuilder(), $server, $frame, $userMessage);
        }
    
        public function builderTask($fn, $server, $userMessage)
        {
            $this->reflection->getMethod($fn)->invoke($this->autoBuilder(), $server, $userMessage);
        }
    
        public function autoBuilder()
        {
            #对构造函数赋值
            return $this->batchInstantiation($this->getPrototypeController($this->reflection)#获得字串
            );
        }
    
        protected final function getPrototypeController(\ReflectionClass $object)
        {
            $prototype = false;
            //批量从反射类中获取原型字串
            foreach ($object->getConstructor()->getParameters() as $parameter)
            {
                $prototype[] = $parameter->getClass()->name;
            }
    
            return $prototype ?: [];
        }
    
        protected final function batchInstantiation(array $prototypeArr)
        {
            foreach ($prototypeArr as $item)
            {
                $container = new container($item);
                $insArr[]  = $container->autoBuilder();//进行递归注入
            }
    
            return empty($prototypeArr) ? $this->reflection->newInstance() : $this->reflection->newInstanceArgs($insArr);
        }
    }
    

    有了这个简易的装箱类后,可以着手实现类的路由功能,我们首先创建 composer.json,键入如下内容。

    {
        "require": {
     
        },
        "autoload": {
            "psr-4": {
            "App\\": "App/"
            }
       }
    }
    

    下一步,我们需要创建一个处理路由的类,这个类在常规的框架中,一般用来映射 http 请求到对应的类的函数上,而在 swoole 里,请求会来自长连接。那么在 route 类中则需要做相应的处理。

    class Route
    {
        public $websocketServer;
        public $model;
        public $cache;
        public function __construct() {
            $this->websocketServer = new \swoole_websocket_server("0.0.0.0", "8002");
        }
        public function start_ws() {
            // 这里设置一些 swoole 的参数 ...
            // 最后执行启动 swoole
            $this->websocketServer->start();
        }
       
        public function ws_onMessage(\swoole_websocket_server $server, $frame)
        {
            $userMessage = $this->filter_arr(json_decode($frame->data, true));
            if (!$userMessage) {
                return false;
            }
            
            if (!$userMessage['type'] || !$userMessage['action']) {
                return $this->call_shell("Type or action not found! ");
            }
            //使用依赖注入容器做伪路由
            $App = new Container('\App\Controller\\'.$userMessage['type']);
            return $App->builderController($userMessage['action'], $server, $frame,$userMessage);
        }
        
    }
    

    最后一步,创建一个入口文件,引导路由类的执行。

    <?php
    require "vendor/autoload.php";
    
    use App\Server\Route;
    
    $App = new Route();
    $App->start_ws();
    
    10 条回复    2021-03-18 22:10:58 +08:00
    GM
        1
    GM   50 天前
    你好,Swoft 可以参考一下
    to2false
        2
    to2false   50 天前
    你好,hyperf 可以参考一下
    qq1340691923
        3
    qq1340691923   50 天前 via iPhone
    你好,es 可以参考一下
    ben1024
        4
    ben1024   50 天前
    可以试试 hyperf,自己练习那就加油
    sorshion
        5
    sorshion   50 天前
    你好,hyperf 可以参考一下
    agdhole
        6
    agdhole   49 天前 via iPhone
    你好,fiber 了解一下
    ritaswc
        7
    ritaswc   49 天前
    你好,hyperf 可以参考一下
    xiaotianhu
        8
    xiaotianhu   49 天前
    你好,laravel-s 可以了解一下
    JaguarJack
        9
    JaguarJack   49 天前   ❤️ 2
    你好,Laravel-Octane 了解一下!
    limingxinleo
        10
    limingxinleo   49 天前 via iPhone
    你好,一定要自己尝试一下,swoole 写起来真的很爽
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1369 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 18ms · UTC 17:11 · PVG 01:11 · LAX 10:11 · JFK 13:11
    ♥ Do have faith in what you're doing.