这里我们以Hyperf为例进行学习,由于大体上这些框架是差不多的,实在便是它有啥我赶紧也弄一个,如果要运用在生产环境上,还须要根据自己的需求进行选择,详细可以看下项目的掩护进度、社区的生动程度等,Hyperf是Swoole官方推举的框架,开拓职员也是swoole的核心职员。
无论是Hyperf还是Laravel、Yii等等,学习一个框架,我们首先要学习人家的官方文档,至少要浏览一遍知道他的基本组成、功能点。
Hyperf供应的功能除了之前php-fpm运行模式下的框架功能如路由、事宜、中间件、要求、相应、数据库之外,加入了如表明、微做事组件、全协程支持等基于swoole的功能。

本次我们基于2.0.3版本进行学习,不同的版本之前可能略有差异。
我们可以按照文档中的步骤进行安装即可,本机或者docker中,这次我们只看一下Hyperf的启动流程。
启动流程剖析在运行之前我们须要看一下官方文档,理解两个东西
Hyperf的ConfigProvider思想 https://hyperf.wiki/2.0/#/zh-cn/component-guide/configprovider,这是组件化的根本,每个组件须要一个ConfigProvider文件,里面供应依赖处理、目录扫描等配置HyperfDi的利用:https://hyperf.wiki/2.0/#/zh-cn/di , 其他传统框架如Laravel也有Container的观点实行入口文件
./bin/hyperf.php start
hyperf.php
// Self-called anonymous function that creates its own scope and keep the global namespace clean.(function () { Hyperf\Di\ClassLoader::init();// 类加载、表明扫描等 / @var \Psr\Container\ContainerInterface $container / $container = require BASE_PATH . '/config/container.php';// 初始化容器// 初始化consoleApplication $application = $container->get(\Hyperf\Contract\ApplicationInterface::class);// 启动 $application->run();})();
在实行前会进行配置的扫描、依赖的处理、表明的扫描等等
通过ClassLoader::init(); 这里面一堆东西,什么类加载、注册、扫描表明、类map等等大家可以逐步看。
进入到container.php
// (new DefinitionSourceFactory(true))() 这个语法把稳,工具当方法调用,会触发__invoke方法$container = new Container((new DefinitionSourceFactory(true))());if (! $container instanceof \Psr\Container\ContainerInterface) { throw new RuntimeException('The dependency injection container is invalid.');}return ApplicationContext::setContainer($container);
那么上面DefinitionSourceFactory干的事便是通过上面提到的ConfigProvider来办理依赖的问题,Hyperf的每个组件都须要有ConfigProvider文件,ConfigProvider在启动的时候会进行处理,个中的denpendencies便是处理Inerface与对应的Definition。
那么我们从vendor/hyperf/framework/src/ConfigProvider.php 可以看到ApplicationInterface的实现是ApplicationFactory
初始化命令行程序:symfony/console/application ,这是公共组件,Laravel也用的这个解析输入的command: 如 hyperf.php start 得到 vendor/hyperf/server/src/Command/StartServer ,继续自Symfony/console/Command并实行StartServer->execute检说情况 checkEnvironment获取 config/autoload/server.php 配置解析配置根据server里面的type去初始化serverstartServer.php调用vendor/hyperf/server/src/Server->init后面的事情便是初始化server了,type可以是SERVER_HTTP, SERVER_WEBSOCKET等设置on 回调处理如onWorkerStart, onRequest等等这里会扫描路由,包括routes.php及利用表明的路由,组装成url->handleClass的映射,如 api/v1/login -> /UserController->login 类似这样的调用server->start 启动做事, 这里后面就进入到swoole的实行流程了以Http做事为例子,当有要求进来时,会触发onRequest事宜也便是vendor/hyperf/http-server/src/Server->onRequest这个流程与其他框架就差不多了获取要求参数,从路由解析出controller->methodmiddleware处理末了到达controller进行处理返回response
部分代码:
startServer.php
protected function execute(InputInterface $input, OutputInterface $output) { $this->checkEnvironment($output); $serverFactory = $this->container->get(ServerFactory::class) ->setEventDispatcher($this->container->get(EventDispatcherInterface::class)) ->setLogger($this->container->get(StdoutLoggerInterface::class)); // 获取配置 config/autoload/server.php $serverConfig = $this->container->get(ConfigInterface::class)->get('server', []); if (! $serverConfig) { throw new InvalidArgumentException('At least one server should be defined.'); }// 初始化配置 $serverFactory->configure($serverConfig); Runtime::enableCoroutine(true, swoole_hook_flags());// server->start() $serverFactory->start(); return 0; }
Server.php
protected function initServers(ServerConfig $config) { $servers = $this->sortServers($config->getServers());// config/autoload/server.php 可以配置多个server foreach ($servers as $server) { $name = $server->getName(); $type = $server->getType(); $host = $server->getHost(); $port = $server->getPort(); $sockType = $server->getSockType(); $callbacks = $server->getCallbacks(); if (! $this->server instanceof SwooleServer) { // 根据类型初始化server 如HTTPServer WebSocketServer $this->server = $this->makeServer($type, $host, $port, $config->getMode(), $sockType); $callbacks = array_replace($this->defaultCallbacks(), $config->getCallbacks(), $callbacks);// 设置回调 $this->registerSwooleEvents($this->server, $callbacks, $name); $this->server->set(array_replace($config->getSettings(), $server->getSettings())); ServerManager::add($name, [$type, current($this->server->ports)]); if (class_exists(BeforeMainServerStart::class)) { // Trigger BeforeMainServerStart event, this event only trigger once before main server start. $this->eventDispatcher->dispatch(new BeforeMainServerStart($this->server, $config->toArray())); } } else { / @var bool|\Swoole\Server\Port $slaveServer / $slaveServer = $this->server->addlistener($host, $port, $sockType); if (! $slaveServer) { throw new \RuntimeException("Failed to listen server port [{$host}:{$port}]"); } $server->getSettings() && $slaveServer->set(array_replace($config->getSettings(), $server->getSettings())); $this->registerSwooleEvents($slaveServer, $callbacks, $name); ServerManager::add($name, [$type, $slaveServer]); } // Trigger beforeStart event. if (isset($callbacks[SwooleEvent::ON_BEFORE_START])) { [$class, $method] = $callbacks[SwooleEvent::ON_BEFORE_START]; if ($this->container->has($class)) { $this->container->get($class)->{$method}(); } } if (class_exists(BeforeServerStart::class)) { // Trigger BeforeServerStart event. $this->eventDispatcher->dispatch(new BeforeServerStart($name)); } } }
启动流程图
要求处理
个中框架中的公共组件可以看下:
路由处理:fastRoutehttps://github.com/nikic/FastRouteConsole及Command处理:https://github.com/symfony/symfony/tree/master/src/Symfony/Component/Console