IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> hyperf的启动源码分析 -> 正文阅读

[PHP知识库]hyperf的启动源码分析

heyperf 是php 的一款协程框架, 我们在安装好 hyperf 之后, 在命令行使用

php bin/hyperf.php start 就可以将它启动, 那么这行命令到底做了什么工作,本人分析了一下源码, 大至看懂了一些, 这里做一下笔记

从入口进入看一下代码 也就是 hyperf.php

//------------------------第一段---------------------
ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');
ini_set('memory_limit', '1G');
error_reporting(E_ALL);
! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);
//-------------------------第二段----------------------------
require BASE_PATH . '/vendor/autoload.php';
//-------------------------第三段----------------------------------
// Self-called anonymous function that creates its own scope and keep the global namespace clean.
(function () {
    Hyperf\Di\ClassLoader::init();
    $container = require BASE_PATH . '/config/container.php';
    $application = $container->get(Hyperf\Contract\ApplicationInterface::class);
    $application->run();
})();

从上现有代码中 三段代码中, 我们可以看到
第一段 定义一些常量, 修改一些php.ini中的配置,这个不用多说
第二段 composer 引入autoload.php , 这个也不用多说
第三段, 我们先看一下, 是一个匿名函数, 并且后面加了一个小括号, 说明就是一个立即执行的函数, 不懂为什么要这样写, 但是其作用就是, 执行了那段函数体中的代码
第一行 Hyperf\Di\ClassLoader::init(); 它的作用就是 psr-4 中的 autoload的一通加载, 反正就是自动加载了很多类
第二行 $container = require BASE_PATH . ‘/config/container.php’; 引入了 一个文件, 我们进入这个文件

//新建了一个container 容器
$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);

这一行代码 $container = new Container((new DefinitionSourceFactory(true))()); 仔细看一下参数, (new classname())() 这种写法, 其实就是执行了 类中的 __invoke() 方法,
那么我们再进入 DefinitionSourceFactory 类中, 查看一下 __invoke()方法

class DefinitionSourceFactory
{
    /**
     * @var bool
     */
    protected $enableCache = false;
    /**
     * @var string
     */
    protected $baseUri;

    public function __construct(bool $enableCache = false)
    {
        $this->enableCache = $enableCache;
        if (! defined('BASE_PATH')) {
            throw new Exception('BASE_PATH is not defined.');
        }
        $this->baseUri = BASE_PATH;
    }
    public function __invoke()
    {
        $configDir = $this->baseUri . '/config';
        $configFromProviders = [];
        //所有的插件都会有一个 ProviderConfig.php文件, 同时这个 ProviderConfig 会有一个 __invoke()的方法, 这个方法返回的是一个类似配置的文件数组
        //如 文件的扫瞄路径  hyperf-di的依赖 map 信息等  如下面的
        if (class_exists(ProviderConfig::class)) {
            //在load方法中使用foreach 方法得到了所有插件中的 prviderconfig的配置
            $configFromProviders = ProviderConfig::load();
        }
        $serverDependencies = $configFromProviders['dependencies'] ?? [];
        if (file_exists($configDir . '/autoload/dependencies.php')) {
            //得到所有的映射关系, 如果我们自已配置了 /autoload/dependncies.php, 把我们自己的配置也一起合并
            $definitions = include $configDir . '/autoload/dependencies.php';
            $serverDependencies = array_replace($serverDependencies, $definitions ?? []);
        }
        return new DefinitionSource($serverDependencies);
    }
}

在 __invoke()方法中, class_exists(ProviderConfig::class) 这个判断返回的是 true,
所以会执行 $configFromProviders = ProviderConfig::load();, 我们进入 load() 方法,

   public static function load(): array
   {
       if (! static::$providerConfigs) {
           $providers = Composer::getMergedExtra('hyperf')['config'] ?? [];
           var_dump($providers);
           exit;
           static::$providerConfigs = static::loadProviders($providers);
       }
       return static::$providerConfigs;
   }

因为有点看不懂 Composer::getMergedExtra(‘hyperf’)[‘config’] ?? []; 是在做什么, 所以我把 $providers 打印出来看了一下, 发现是我们安装的所有 插件的 ProviderConfig.php的文件的一个数组
如图
在这里插入图片描述
我们随便打开一个 ConfigProvider 看一下, 发现其格式大至是一样的

Hyperf\Framework\ConfigProvider
在这里插入图片描述
Hyperf\Framework\ConfigProvider
在这里插入图片描述

基本上所有的 providerCofnig.php都是这一样的格式

再看一下 static:: p r o v i d e r C o n f i g s = s t a t i c : : l o a d P r o v i d e r s ( providerConfigs = static::loadProviders( providerConfigs=static::loadProviders(providers); 这一行代码 中的 loadProviders($providers);

protected static function loadProviders(array $providers): array
    {
        $providerConfigs = [];
        foreach ($providers as $provider) {
            if (is_string($provider) && class_exists($provider) && method_exists($provider, '__invoke')) {
                $providerConfigs[] = (new $provider())();
            }
        }
        return static::merge(...$providerConfigs);
    }

可以看到, 它把所有的 ProviderConfig.php 文件都循环了一遍, 并且做了判断, 如果
在这里插入图片描述
数组中的这个类存在, 并且有 __invoke() 方法,就执行invoke(), 把返回后的数组再合并,所以, 我们可以想象返回的数组中有很多的,类似这样的记录

在这里插入图片描述

回到我们看到的 $configFromProviders = ProviderConfig::load(); 这个方法, 我们把 $configFormProviders打印出来看一下
太长了不能截图 复制下来就是下面的这个, 里面有 dependecies annotations listeners commands 等等

array(6) {
  ["dependencies"]=>
  array(21) {
    ["Psr\SimpleCache\CacheInterface"]=>
    string(18) "Hyperf\Cache\Cache"
    ["Hyperf\Contract\ConfigInterface"]=>
    string(27) "Hyperf\Config\ConfigFactory"
    ["Hyperf\DbConnection\Pool\PoolFactory"]=>
    string(36) "Hyperf\DbConnection\Pool\PoolFactory"
    ["Hyperf\Database\Connectors\ConnectionFactory"]=>
    string(44) "Hyperf\Database\Connectors\ConnectionFactory"
    ["Hyperf\Database\ConnectionResolverInterface"]=>
    string(38) "Hyperf\DbConnection\ConnectionResolver"
    ["db.connector.mysql"]=>
    string(41) "Hyperf\Database\Connectors\MySqlConnector"
    ["Hyperf\Database\Migrations\MigrationRepositoryInterface"]=>
    string(54) "Hyperf\DbConnection\DatabaseMigrationRepositoryFactory"
    ["Hyperf\Di\MethodDefinitionCollectorInterface"]=>
    string(35) "Hyperf\Di\MethodDefinitionCollector"
    ["Hyperf\Di\ClosureDefinitionCollectorInterface"]=>
    string(36) "Hyperf\Di\ClosureDefinitionCollector"
    ["Psr\EventDispatcher\ListenerProviderInterface"]=>
    string(36) "Hyperf\Event\ListenerProviderFactory"
    ["Psr\EventDispatcher\EventDispatcherInterface"]=>
    string(35) "Hyperf\Event\EventDispatcherFactory"
    ["Hyperf\ExceptionHandler\Formatter\FormatterInterface"]=>
    string(50) "Hyperf\ExceptionHandler\Formatter\DefaultFormatter"
    ["Hyperf\Contract\ApplicationInterface"]=>
    string(35) "Hyperf\Framework\ApplicationFactory"
    ["Hyperf\Contract\StdoutLoggerInterface"]=>
    string(36) "Hyperf\Framework\Logger\StdoutLogger"
    ["Hyperf\HttpMessage\Server\RequestParserInterface"]=>
    string(40) "Hyperf\HttpMessage\Server\Request\Parser"
    ["Hyperf\HttpServer\Contract\RequestInterface"]=>
    string(25) "Hyperf\HttpServer\Request"
    ["Psr\Http\Message\ServerRequestInterface"]=>
    string(25) "Hyperf\HttpServer\Request"
    ["Hyperf\HttpServer\Contract\ResponseInterface"]=>
    string(26) "Hyperf\HttpServer\Response"
    ["Swoole\Server"]=>
    string(33) "Hyperf\Server\SwooleServerFactory"
    ["Symfony\Component\Serializer\Serializer"]=>
    string(41) "Hyperf\Utils\Serializer\SerializerFactory"
    ["Hyperf\Contract\NormalizerInterface"]=>
    string(40) "Hyperf\Utils\Serializer\SimpleNormalizer"
  }
  ["listeners"]=>
  array(12) {
    [0]=>
    string(36) "Hyperf\Cache\Listener\DeleteListener"
    [1]=>
    string(54) "Hyperf\Config\Listener\RegisterPropertyHandlerListener"
    [2]=>
    string(63) "Hyperf\DbConnection\Listener\RegisterConnectionResolverListener"
    [3]=>
    string(57) "Hyperf\ExceptionHandler\Listener\ExceptionHandlerListener"
    [4]=>
    string(48) "Hyperf\ModelListener\Listener\ModelEventListener"
    ["Hyperf\ModelListener\Listener\ModelHookEventListener"]=>
    int(99)
    [5]=>
    string(43) "Hyperf\Process\Listener\BootProcessListener"
    [6]=>
    string(54) "Hyperf\Process\Listener\LogAfterProcessStoppedListener"
    [7]=>
    string(53) "Hyperf\Process\Listener\LogBeforeProcessStartListener"
    [8]=>
    string(46) "Hyperf\Server\Listener\StoreServerNameListener"
    [9]=>
    string(47) "Hyperf\Server\Listener\AfterWorkerStartListener"
    [10]=>
    string(47) "Hyperf\Server\Listener\InitProcessTitleListener"
  }
  ["annotations"]=>
  array(2) {
    ["scan"]=>
    array(2) {
      ["paths"]=>
      array(18) {
        [0]=>
        string(46) "/var/www/hyperf/hyperf/vendor/hyperf/cache/src"
        [1]=>
        string(47) "/var/www/hyperf/hyperf/vendor/hyperf/config/src"
        [2]=>
        string(54) "/var/www/hyperf/hyperf/vendor/hyperf/db-connection/src"
        [3]=>
        string(43) "/var/www/hyperf/hyperf/vendor/hyperf/di/src"
        [4]=>
        string(51) "/var/www/hyperf/hyperf/vendor/hyperf/dispatcher/src"
        [5]=>
        string(46) "/var/www/hyperf/hyperf/vendor/hyperf/event/src"
        [6]=>
        string(58) "/var/www/hyperf/hyperf/vendor/hyperf/exception-handler/src"
        [7]=>
        string(50) "/var/www/hyperf/hyperf/vendor/hyperf/framework/src"
        [8]=>
        string(47) "/var/www/hyperf/hyperf/vendor/hyperf/guzzle/src"
        [9]=>
        string(52) "/var/www/hyperf/hyperf/vendor/hyperf/http-server/src"
        [10]=>
        string(47) "/var/www/hyperf/hyperf/vendor/hyperf/logger/src"
        [11]=>
        string(47) "/var/www/hyperf/hyperf/vendor/hyperf/memory/src"
        [12]=>
        string(55) "/var/www/hyperf/hyperf/vendor/hyperf/model-listener/src"
        [13]=>
        string(45) "/var/www/hyperf/hyperf/vendor/hyperf/pool/src"
        [14]=>
        string(48) "/var/www/hyperf/hyperf/vendor/hyperf/process/src"
        [15]=>
        string(47) "/var/www/hyperf/hyperf/vendor/hyperf/server/src"
        [16]=>
        string(46) "/var/www/hyperf/hyperf/vendor/hyperf/utils/src"
        [17]=>
        string(48) "/var/www/hyperf/hyperf/vendor/hyperf/devtool/src"
      }
      ["collectors"]=>
      array(4) {
        [0]=>
        string(35) "Hyperf\Cache\CacheListenerCollector"
        [1]=>
        string(40) "Hyperf\Di\Annotation\AnnotationCollector"
        [2]=>
        string(36) "Hyperf\Di\Annotation\AspectCollector"
        [3]=>
        string(48) "Hyperf\ModelListener\Collector\ListenerCollector"
      }
    }
    ["ignore_annotations"]=>
    array(1) {
      [0]=>
      string(5) "mixin"
    }
  }
  ["publish"]=>
  array(6) {
    [0]=>
    array(4) {
      ["id"]=>
      string(6) "config"
      ["description"]=>
      string(21) "The config for cache."
      ["source"]=>
      string(67) "/var/www/hyperf/hyperf/vendor/hyperf/cache/src/../publish/cache.php"
      ["destination"]=>
      string(48) "/var/www/hyperf/hyperf/config/autoload/cache.php"
    }
    [1]=>
    array(4) {
      ["id"]=>
      string(6) "config"
      ["description"]=>
      string(24) "The config for database."
      ["source"]=>
      string(79) "/var/www/hyperf/hyperf/vendor/hyperf/db-connection/src/../publish/databases.php"
      ["destination"]=>
      string(52) "/var/www/hyperf/hyperf/config/autoload/databases.php"
    }
    [2]=>
    array(4) {
      ["id"]=>
      string(14) "query-listener"
      ["description"]=>
      string(39) "The listener of database to record log."
      ["source"]=>
      string(93) "/var/www/hyperf/hyperf/vendor/hyperf/db-connection/src/../publish/DbQueryExecutedListener.php"
      ["destination"]=>
      string(63) "/var/www/hyperf/hyperf/app/Listener/DbQueryExecutedListener.php"
    }
    [3]=>
    array(4) {
      ["id"]=>
      string(6) "config"
      ["description"]=>
      string(22) "The config for logger."
      ["source"]=>
      string(69) "/var/www/hyperf/hyperf/vendor/hyperf/logger/src/../publish/logger.php"
      ["destination"]=>
      string(49) "/var/www/hyperf/hyperf/config/autoload/logger.php"
    }
    [4]=>
    array(4) {
      ["id"]=>
      string(6) "config"
      ["description"]=>
      string(22) "The config for server."
      ["source"]=>
      string(69) "/var/www/hyperf/hyperf/vendor/hyperf/server/src/../publish/server.php"
      ["destination"]=>
      string(49) "/var/www/hyperf/hyperf/config/autoload/server.php"
    }
    [5]=>
    array(4) {
      ["id"]=>
      string(6) "config"
      ["description"]=>
      string(23) "The config for devtool."
      ["source"]=>
      string(71) "/var/www/hyperf/hyperf/vendor/hyperf/devtool/src/../publish/devtool.php"
      ["destination"]=>
      string(50) "/var/www/hyperf/hyperf/config/autoload/devtool.php"
    }
  }
  ["aspects"]=>
  array(2) {
    [0]=>
    string(36) "Hyperf\Config\Annotation\ValueAspect"
    [1]=>
    string(33) "Hyperf\Di\Annotation\InjectAspect"
  }
  ["commands"]=>
  array(15) {
    [0]=>
    string(37) "Hyperf\Database\Commands\ModelCommand"
    [1]=>
    string(53) "Hyperf\Database\Commands\Migrations\GenMigrateCommand"
    [2]=>
    string(50) "Hyperf\Database\Commands\Migrations\InstallCommand"
    [3]=>
    string(50) "Hyperf\Database\Commands\Migrations\MigrateCommand"
    [4]=>
    string(48) "Hyperf\Database\Commands\Migrations\FreshCommand"
    [5]=>
    string(50) "Hyperf\Database\Commands\Migrations\RefreshCommand"
    [6]=>
    string(48) "Hyperf\Database\Commands\Migrations\ResetCommand"
    [7]=>
    string(51) "Hyperf\Database\Commands\Migrations\RollbackCommand"
    [8]=>
    string(49) "Hyperf\Database\Commands\Migrations\StatusCommand"
    [9]=>
    string(49) "Hyperf\Database\Commands\Seeders\GenSeederCommand"
    [10]=>
    string(44) "Hyperf\Database\Commands\Seeders\SeedCommand"
    [11]=>
    string(33) "Hyperf\Server\Command\StartServer"
    [12]=>
    string(38) "Hyperf\Devtool\Describe\AspectsCommand"
    [13]=>
    string(40) "Hyperf\Devtool\Describe\ListenersCommand"
    [14]=>
    string(37) "Hyperf\Devtool\Describe\RoutesCommand"
  }
}


继续往下走代码
在这里插入图片描述
得到了 configFormProviders 是上面的一堆数组, 它又得我们自定义的配置进行合并, 最终得到 一个 $serverDependencies 的数组做为参数 我们把 $serverDependencies 打印出来看一下

在这里插入图片描述

[“Psr\SimpleCache\CacheInterface”]=>string(18) “Hyperf\Cache\Cache”
[“Hyperf\Contract\ConfigInterface”]=>string(27) “Hyperf\Config\ConfigFactory”
可以看到是这样子的格式的键值对, 这其实就是 container 容器中的键值对,

重点, 说白了, 也就是说 当我们获得容器中的对象时, 它的键就是上图中的键

如:我们想得到一个 Hyperf\Cache\Cache 的实例, 我们就要使用 $container->get(Psr\SimpleCache\CacheInterface::class),得到的对象就是容器中的 Hyperf\Cache\Cache , 这一点很重要, hyperf中很多都是使用这种获取的

继续回到上层的方法如图
在这里插入图片描述
我们对参数研究完毕子, 现在看一下 Container的 构造函数都干了些什么

在这里插入图片描述
前两句定义了两个属性, 在红箭头处 相当于是给 这个 容器中加入了 指向自己的键, 也就是说这三个键都指向了自已

所以当我们使用 $container->get(Psr\Container\ContainerInterface::class) 或者 $container->get(Hyperf\Contract\ContainerInterface::class) 又或者 c o n t a i n e r ? > g e t ( g e t c l a s s ( container->get(get_class( container?>get(getc?lass(container))得到的都是container容器对象这些是题外话, 不重要, 可以不看

在这里插入图片描述
继续往下走, ApplicationContext::setContainer($container); 还是返回了容器对象
返回到上一层代码中

在这里插入图片描述
上面的代码得到了 $container , 然后从容器中得到 键名为 Hyperf\Contract\ApplicationInterface::class 的对象, 那么这里一个什么对象了, 我们应该在 ProviderConfig.php文件中的 dependencies 中去找
最终在这里找到了
在这里插入图片描述
也就是说它实际上是一个 ApplicationFactory::class的一个对象, 同样的了我们要看 ApplicationFactory::class的 __invoke() 方法

class ApplicationFactory
{
    public function __invoke(ContainerInterface $container)
    {
        if ($container->has(EventDispatcherInterface::class)) {
            $eventDispatcher = $container->get(EventDispatcherInterface::class);
            $eventDispatcher->dispatch(new BootApplication());
        }
        $config = $container->get(ConfigInterface::class);
        //这里的config是把所有的 插件中的config 综合在一起

        $commands = $config->get('commands', []);
        //在config中找到 commands 键的配置项
        //var_dump($commands);
        // Append commands that defined by annotation.
        $annotationCommands = [];
        if (class_exists(AnnotationCollector::class) && class_exists(Command::class)) {
            $annotationCommands = AnnotationCollector::getClassesByAnnotation(Command::class);
            $annotationCommands = array_keys($annotationCommands);
        }
        $commands = array_unique(array_merge($commands, $annotationCommands));
        $application = new Application();
        if (isset($eventDispatcher) && class_exists(SymfonyEventDispatcher::class)) {
            $application->setDispatcher(new SymfonyEventDispatcher($eventDispatcher));
        }
        foreach ($commands as $command) {
            $application->add($container->get($command));
        }
        return $application;
    }
}

从上面的代码中我们可以看到, 这其实是 Symfony\Component\Console\Application; 也就是一个命令行的对象, 我们在代码中 把$commands 数组找印出来
在这里插入图片描述
可以看到, 在这段代码中注册了这么多的 命令行代码类, 其中我们开启用的 /bin/hyperf.php start,所以我们看一下 上面的 startServer 类, 就知道,hyperf是怎么启动的了

StartServer.php

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace Hyperf\Server\Command;

use Hyperf\Contract\ConfigInterface;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Engine\Coroutine;
use Hyperf\Server\ServerFactory;
use InvalidArgumentException;
use Psr\Container\ContainerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class StartServer extends Command
{
    /**
     * @var ContainerInterface
     */
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
        parent::__construct('start');
        $this->setDescription('Start hyperf servers.');
    }

    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));

        $serverConfig = $this->container->get(ConfigInterface::class)->get('server', []);
        if (! $serverConfig) {
            throw new InvalidArgumentException('At least one server should be defined.');
        }

        $serverFactory->configure($serverConfig);

        Coroutine::set(['hook_flags' => swoole_hook_flags()]);

        $serverFactory->start();

        return 0;
    }

    private function checkEnvironment(OutputInterface $output)
    {
        if (! extension_loaded('swoole')) {
            return;
        }

        $useShortname = ini_get_all('swoole')['swoole.use_shortname']['local_value'];
        $useShortname = strtolower(trim(str_replace('0', '', $useShortname)));
        if (! in_array($useShortname, ['', 'off', 'false'], true)) {
            $output->writeln('<error>ERROR</error> Swoole short name have to disable before start server, please set swoole.use_shortname = off into your php.ini.');
            exit(SIGTERM);
        }
    }
}

这个类是继承了 Symfony\Component\Console Command的, 所以我们关建看 execute() 方法
而方法中, 我们关键看 $serverFactory->start();
进入 $serverFactory 中, 我们就可以看到一个 getServer方法
在这里插入图片描述
我们把 $serverName 打印出来
在这里插入图片描述
最终我们就看的是 Hyperf\Server\Server 的 start()方法, 启动的服务
启动类就是它了
看一下代码,就可以看个八九不离十的

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace Hyperf\Server;

use Hyperf\Contract\MiddlewareInitializerInterface;
use Hyperf\Framework\Bootstrap;
use Hyperf\Framework\Event\BeforeMainServerStart;
use Hyperf\Framework\Event\BeforeServerStart;
use Hyperf\Server\Exception\RuntimeException;
use Psr\Container\ContainerInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Swoole\Http\Server as SwooleHttpServer;
use Swoole\Server as SwooleServer;
use Swoole\WebSocket\Server as SwooleWebSocketServer;

class Server implements ServerInterface
{
    /**
     * @var bool
     */
    protected $enableHttpServer = false;

    /**
     * @var bool
     */
    protected $enableWebsocketServer = false;

    /**
     * @var SwooleServer
     */
    protected $server;

    /**
     * @var array
     */
    protected $onRequestCallbacks = [];

    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var EventDispatcherInterface
     */
    protected $eventDispatcher;

    public function __construct(ContainerInterface $container, LoggerInterface $logger, EventDispatcherInterface $dispatcher)
    {
        $this->container = $container;
        $this->logger = $logger;
        $this->eventDispatcher = $dispatcher;
    }

    public function init(ServerConfig $config): ServerInterface
    {
        $this->initServers($config);

        return $this;
    }

    public function start()
    {
        $this->server->start();
    }

    public function getServer()
    {
        return $this->server;
    }

    protected function initServers(ServerConfig $config)
    {
        $servers = $this->sortServers($config->getServers());

        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) {
                $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[Event::ON_BEFORE_START])) {
                [$class, $method] = $callbacks[Event::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));
            }
        }
    }

    /**
     * @param Port[] $servers
     * @return Port[]
     */
    protected function sortServers(array $servers)
    {
        $sortServers = [];
        foreach ($servers as $server) {
            switch ($server->getType() ?? 0) {
                case ServerInterface::SERVER_HTTP:
                    $this->enableHttpServer = true;
                    if (! $this->enableWebsocketServer) {
                        array_unshift($sortServers, $server);
                    } else {
                        $sortServers[] = $server;
                    }
                    break;
                case ServerInterface::SERVER_WEBSOCKET:
                    $this->enableWebsocketServer = true;
                    array_unshift($sortServers, $server);
                    break;
                default:
                    $sortServers[] = $server;
                    break;
            }
        }

        return $sortServers;
    }

    protected function makeServer(int $type, string $host, int $port, int $mode, int $sockType)
    {
        switch ($type) {
            case ServerInterface::SERVER_HTTP:
                return new SwooleHttpServer($host, $port, $mode, $sockType);
            case ServerInterface::SERVER_WEBSOCKET:
                return new SwooleWebSocketServer($host, $port, $mode, $sockType);
            case ServerInterface::SERVER_BASE:
                return new SwooleServer($host, $port, $mode, $sockType);
        }

        throw new RuntimeException('Server type is invalid.');
    }

    /**
     * @param \Swoole\Server\Port|SwooleServer $server
     */
    protected function registerSwooleEvents($server, array $events, string $serverName): void
    {
        foreach ($events as $event => $callback) {
            if (! Event::isSwooleEvent($event)) {
                continue;
            }
            if (is_array($callback)) {
                [$className, $method] = $callback;
                if (array_key_exists($className . $method, $this->onRequestCallbacks)) {
                    $this->logger->warning(sprintf('%s will be replaced by %s. Each server should have its own onRequest callback. Please check your configs.', $this->onRequestCallbacks[$className . $method], $serverName));
                }

                $this->onRequestCallbacks[$className . $method] = $serverName;
                $class = $this->container->get($className);
                if (method_exists($class, 'setServerName')) {
                    // Override the server name.
                    $class->setServerName($serverName);
                }
                if ($class instanceof MiddlewareInitializerInterface) {
                    $class->initCoreMiddleware($serverName);
                }
                $callback = [$class, $method];
            }
            $server->on($event, $callback);
        }
    }

    protected function defaultCallbacks()
    {
        $hasCallback = class_exists(Bootstrap\StartCallback::class)
            && class_exists(Bootstrap\ManagerStartCallback::class)
            && class_exists(Bootstrap\WorkerStartCallback::class);

        if ($hasCallback) {
            $callbacks = [
                Event::ON_MANAGER_START => [Bootstrap\ManagerStartCallback::class, 'onManagerStart'],
                Event::ON_WORKER_START => [Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
                Event::ON_WORKER_STOP => [Bootstrap\WorkerStopCallback::class, 'onWorkerStop'],
                Event::ON_WORKER_EXIT => [Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
            ];
            if ($this->server->mode === SWOOLE_BASE) {
                return $callbacks;
            }

            return array_merge([
                Event::ON_START => [Bootstrap\StartCallback::class, 'onStart'],
            ], $callbacks);
        }

        return [
            Event::ON_WORKER_START => function (SwooleServer $server, int $workerId) {
                printf('Worker %d started.' . PHP_EOL, $workerId);
            },
        ];
    }
}


以上就是 hyperf的启动源码分析, 功夫不好, 有些地方看不太懂, 就用了 var_dump 大法, 见笑, 总算还可以看到头绪,欣慰

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-01 11:41:35  更:2021-09-01 11:43:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 10:33:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码