這次我們學習下基於Swoole的PHP框架的使用,swoole的框架很多,目前主流的有Swoft(swoft.org)、Hyperf(hyperf.io)、EasySwoole(easyswoole.com)。
這裡我們以Hyperf為例進行學習,因為大體上這些框架是差不多的,其實就是它有啥我趕緊也弄一個,如果要應用在生產環境上,還需要根據自己的需求進行選擇,具體可以看下項目的維護進度、社區的活躍程度等,Hyperf是Swoole官方推薦的框架,開發人員也是swoole的核心人員。
無論是Hyperf還是Laravel、Yii等等,學習一個框架,我們首先要學習人家的官方文檔,至少要瀏覽一遍知道他的基本組成、功能點。
Hyperf提供的功能除了之前php-fpm運行模式下的框架功能如路由、事件、中間件、請求、響應、資料庫之外,加入了如註解、微服務組件、全協程支持等基於swoole的功能。
本次我們基於2.0.3版本進行學習,不同的版本之前可能略有差異。
我們可以按照文檔中的步驟進行安裝即可,本機或者docker中,這次我們只看一下Hyperf的啟動流程。
在運行之前我們需要看一下官方文檔,了解兩個東西
執行入口文件
./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 . &39;;// 初始化容器 // 初始化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(&39;);}return ApplicationContext::setContainer($container);
那麼上面DefinitionSourceFactory幹的事就是通過上面提到的ConfigProvider來解決依賴的問題,Hyperf的每個組件都需要有ConfigProvider文件,ConfigProvider在啟動的時候會進行處理,其中的denpendencies就是處理Inerface與對應的Definition。
那麼我們從vendor/hyperf/framework/src/ConfigProvider.php 可以看到ApplicationInterface的實現是ApplicationFactory
部分代碼:
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(&39;, []); if (! $serverConfig) { throw new InvalidArgumentException(&39;); } // 初始化配置 $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(&34;); } $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)); } } }
其中框架中的公共組件可以看下: