itxiao6 / laravel-s
🚀 LaravelS: 使用 Swoole 加速 Laravel/Lumen,让我们飞起来。
Requires
- php: >=5.5.9
Suggests
- ext-inotify: Inotify, used to reload all worker processes when your code is modified.
- ext-swoole: Event-driven asynchronous & concurrent & coroutine networking engine with high performance for PHP, require >= 1.7.19.
- dev-master
- v2.0.0-Alpha
- v1.11.3
- v1.11.2
- v1.11.1
- v1.11.0
- v1.10.19
- v1.10.18
- v1.10.17
- v1.10.16
- v1.10.15
- v1.10.14
- v1.10.13
- v1.10.12
- v1.10.11
- v1.10.10
- v1.10.9
- v1.10.8
- v1.10.7
- v1.10.6
- v1.10.5
- v1.10.3
- v1.10.2
- v1.10.1
- v1.10.0
- v1.9.17
- v1.9.16
- v1.9.15
- v1.9.14
- v1.9.13
- v1.9.12
- v1.9.11
- v1.9.10
- v1.9.9
- v1.9.8
- v1.9.7
- v1.9.6
- v1.9.5
- v1.9.4
- v1.9.2
- v1.9.1
- v1.9.0
- v1.8.14
- v1.8.13
- v1.8.12
- v1.8.11
- v1.8.10
- v1.8.9
- v1.8.8
- v1.8.7
- v1.8.6
- v1.8.5
- v1.8.4
- v1.8.3
- v1.8.2
- v1.8.1
- v1.8.0
- v1.7.14
- v1.7.13
- v1.7.12
- v1.7.11
- v1.7.10
- v1.7.9
- v1.7.8
- v1.7.7
- v1.7.6
- v1.7.5
- v1.7.4
- v1.7.3
- v1.7.1
- v1.7.0
- v1.6.13
- v1.6.12
- v1.6.11
- v1.6.10
- v1.6.9
- v1.6.8
- v1.6.7
- v1.6.6
- v1.6.5
- v1.6.4
- v1.6.3
- v1.6.2
- v1.6.1
- v1.6.0
- v1.5.3
- v1.5.2
- v1.5.1
- v1.5.0
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.6
- v1.3.5
- v1.3.4
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.2
- v1.1.11
- v1.1.10
- v1.1.9
- v1.1.8
- v1.1.7
- v1.1.6
- v1.1.5
- v1.1.4
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.1
- v1.0.0
- dev-feature/coroutine_clients
- dev-feature/connection_pool
This package is auto-updated.
Last update: 2024-09-27 17:10:54 UTC
README
_ _ _____
| | | |/ ____|
| | __ _ _ __ __ ___ _____| | (___
| | / _` | '__/ _` \ \ / / _ \ |\___ \
| |___| (_| | | | (_| |\ V / __/ |____) |
|______\__,_|_| \__,_| \_/ \___|_|_____/
🚀 通过
Swoole加速 Laravel/Lumen,让我们飞起来。
功能
-
内置 Http/WebSocket 服务器
-
内存驻留
-
优雅重启
-
代码修改时自动重启
-
支持 Laravel/Lumen,兼容性好
-
简单易用
要求
安装
# Run in the root path of your Laravel/Lumen project. composer require "hhxsv5/laravel-s:~1.0" -vvv # Make sure that your composer.lock file is under the VCS
2. 注册服务提供者。
Laravel: 在config/app.php文件中
'providers' => [ //... Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class, ],
Lumen: 在bootstrap/app.php文件中
$app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);
3. 发布配置。
建议每次升级 LaravelS 后都进行发布
php artisan laravels publish
特别针对 Lumen: 您无需在 bootstrap/app.php 文件中手动加载此配置,LaravelS 会自动加载。
// Unnecessary to call configure() $app->configure('laravels');
4. 修改 config/laravels.php:监听 IP、监听端口,参考 设置。
运行示例
php artisan laravels {start|stop|restart|reload|publish}
与 Nginx 合作(推荐)
gzip on; gzip_min_length 1024; gzip_comp_level 2; gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml; gzip_vary on; gzip_disable "msie6"; upstream laravels { server 192.168.0.1:5200 weight=5 max_fails=3 fail_timeout=30s; #server 192.168.0.2:5200 weight=3 max_fails=3 fail_timeout=30s; #server 192.168.0.3:5200 backup; } server { listen 80; server_name laravels.com; root /xxxpath/laravel-s-test/public; access_log /yyypath/log/nginx/$server_name.access.log main; autoindex off; index index.html index.htm; # Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource. location / { try_files $uri @laravels; } # Response 404 directly when request the PHP file, to avoid exposing public/*.php #location ~* \.php$ { # return 404; #} location @laravels { proxy_http_version 1.1; # proxy_connect_timeout 60s; # proxy_send_timeout 60s; # proxy_read_timeout 120s; proxy_set_header Connection "keep-alive"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header Scheme $scheme; proxy_set_header Server-Protocol $server_protocol; proxy_set_header Server-Name $server_name; proxy_set_header Server-Addr $server_addr; proxy_set_header Server-Port $server_port; proxy_pass http://laravels; } }
与 Apache 合作
LoadModule proxy_module /yyypath/modules/mod_deflate.so <IfModule deflate_module> SetOutputFilter DEFLATE DeflateCompressionLevel 2 AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml </IfModule> <VirtualHost *:80> ServerName www.laravels.com ServerAdmin hhxsv5@sina.com DocumentRoot /xxxpath/laravel-s-test/public; DirectoryIndex index.html index.htm <Directory "/"> AllowOverride None Require all granted </Directory> LoadModule proxy_module /yyypath/modules/mod_proxy.so LoadModule proxy_module /yyypath/modules/mod_proxy_balancer.so LoadModule proxy_module /yyypath/modules/mod_lbmethod_byrequests.so.so LoadModule proxy_module /yyypath/modules/mod_proxy_http.so.so LoadModule proxy_module /yyypath/modules/mod_slotmem_shm.so LoadModule proxy_module /yyypath/modules/mod_rewrite.so ProxyRequests Off ProxyPreserveHost On <Proxy balancer://laravels> BalancerMember http://192.168.1.1:8011 loadfactor=7 #BalancerMember http://192.168.1.2:8011 loadfactor=3 #BalancerMember http://192.168.1.3:8011 loadfactor=1 status=+H ProxySet lbmethod=byrequests </Proxy> #ProxyPass / balancer://laravels/ #ProxyPassReverse / balancer://laravels/ # Apache handles the static resources, LaravelS handles the dynamic resource. RewriteEngine On RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://laravels/%{REQUEST_URI} [P,L] ErrorLog ${APACHE_LOG_DIR}/www.laravels.com.error.log CustomLog ${APACHE_LOG_DIR}/www.laravels.com.access.log combined </VirtualHost>
启用 WebSocket 服务器
WebSocket 服务器监听地址与 Http 服务器相同。
1. 创建 WebSocket 处理器类,并实现接口 WebSocketHandlerInterface。
namespace App\Services; use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface; /** * @see https://www.swoole.co.uk/docs/modules/swoole-websocket-server */ class WebSocketService implements WebSocketHandlerInterface { // Declare constructor without parameters public function __construct() { } public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request) { // Laravel has finished its lifetime before triggering onOpen event, so Laravel's Request & Session are available here, Request is readable only, Session is readable & writable both. \Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]); $server->push($request->fd, 'Welcome to LaravelS'); // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame) { \Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]); $server->push($frame->fd, date('Y-m-d H:i:s')); // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } public function onClose(\swoole_websocket_server $server, $fd, $reactorId) { // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } }
2. 修改 config/laravels.php。
// ... 'websocket' => [ 'enable' => true, 'handler' => \App\Services\WebSocketService::class, ], 'swoole' => [ //... // Must set dispatch_mode in (2, 4, 5), see https://www.swoole.co.uk/docs/modules/swoole-server/configuration 'dispatch_mode' => 2, //... ], // ...
3. 使用 swoole_table 绑定 FD & UserId,可选,参考 Swoole Table 示例。您还可以使用其他全局存储服务,如 Redis/Memcached/MySQL,但请注意,多个 Swoole 服务器 之间 FD 可能会冲突。
4. 与 Nginx 合作(推荐)
参考 WebSocket 代理
map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream laravels { server 192.168.0.1:5200 weight=5 max_fails=3 fail_timeout=30s; #server 192.168.0.2:5200 weight=3 max_fails=3 fail_timeout=30s; #server 192.168.0.3:5200 backup; } server { listen 80; server_name laravels.com; root /xxxpath/laravel-s-test/public; access_log /yyypath/log/nginx/$server_name.access.log main; autoindex off; index index.html index.htm; # Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource. location / { try_files $uri @laravels; } # Response 404 directly when request the PHP file, to avoid exposing public/*.php #location ~* \.php$ { # return 404; #} # Http and WebSocket are concomitant, Nginx identifies them by "location" # Javascript: var ws = new WebSocket("ws://laravels.com/ws"); location =/ws { proxy_http_version 1.1; # proxy_connect_timeout 60s; # proxy_send_timeout 60s; # proxy_read_timeout: Nginx will close the connection if client does not send data to server in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole # proxy_read_timeout 60s; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header Scheme $scheme; proxy_set_header Server-Protocol $server_protocol; proxy_set_header Server-Name $server_name; proxy_set_header Server-Addr $server_addr; proxy_set_header Server-Port $server_port; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_pass http://laravels; } location @laravels { proxy_http_version 1.1; # proxy_connect_timeout 60s; # proxy_send_timeout 60s; # proxy_read_timeout 60s; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header Scheme $scheme; proxy_set_header Server-Protocol $server_protocol; proxy_set_header Server-Name $server_name; proxy_set_header Server-Addr $server_addr; proxy_set_header Server-Port $server_port; proxy_pass http://laravels; } }
监听事件
系统事件
通常,您可以重置/销毁一些
全局/静态变量,或更改当前的请求/响应对象。
laravels.received_request在 LaravelS 将swoole_http_request解析为Illuminate\Http\Request之后,在 Laravel 的 Kernel 处理此请求之前。
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot` // If no variable $events, you can also call Facade \Event::listen(). $events->listen('laravels.received_request', function (\Illuminate\Http\Request $req, $app) { $req->query->set('get_key', 'hhxsv5');// Change query of request $req->request->set('post_key', 'hhxsv5'); // Change post of request });
laravels.generated_response在 Laravel 的 Kernel 处理请求之后,在 LaravelS 将Illuminate\Http\Response解析为swoole_http_response之前。
// Edit file `app/Providers/EventServiceProvider.php`, add the following code into method `boot` // If no variable $events, you can also call Facade \Event::listen(). $events->listen('laravels.generated_response', function (\Illuminate\Http\Request $req, \Symfony\Component\HttpFoundation\Response $rsp, $app) { $rsp->headers->set('header-key', 'hhxsv5');// Change header of response });
自定义异步事件
此功能依赖于
Swoole的AsyncTask,您首先需要在config/laravels.php中设置swoole.task_worker_num。异步事件处理性能受 Swoole 任务进程数的影响,您需要适当地设置 task_worker_num。
1. 创建事件类。
use Hhxsv5\LaravelS\Swoole\Task\Event; class TestEvent extends Event { private $data; public function __construct($data) { $this->data = $data; } public function getData() { return $this->data; } }
2. 创建监听器类。
use Hhxsv5\LaravelS\Swoole\Task\Event; use Hhxsv5\LaravelS\Swoole\Task\Listener; class TestListener1 extends Listener { // Declare constructor without parameters public function __construct() { } public function handle(Event $event) { \Log::info(__CLASS__ . ':handle start', [$event->getData()]); sleep(2);// Simulate the slow codes // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } }
3. 绑定事件 & 监听器。
// Bind event & listeners in file "config/laravels.php", one event => many listeners [ // ... 'events' => [ \App\Tasks\TestEvent::class => [ \App\Tasks\TestListener1::class, //\App\Tasks\TestListener2::class, ], ], // ... ];
4. 触发事件。
// Create instance of event and fire it, "fire" is asynchronous. use Hhxsv5\LaravelS\Swoole\Task\Event; $success = Event::fire(new TestEvent('event data')); var_dump($success);// Return true if sucess, otherwise false
异步任务队列
此功能依赖于
Swoole的AsyncTask,您首先需要在config/laravels.php中设置swoole.task_worker_num。任务处理性能受 Swoole 任务进程数的影响,您需要适当地设置 task_worker_num。
1. 创建任务类。
use Hhxsv5\LaravelS\Swoole\Task\Task; class TestTask extends Task { private $data; private $result; public function __construct($data) { $this->data = $data; } // The logic of task handling, run in task process, CAN NOT deliver task public function handle() { \Log::info(__CLASS__ . ':handle start', [$this->data]); sleep(2);// Simulate the slow codes // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them $this->result = 'the result of ' . $this->data; } // Optional, finish event, the logic of after task handling, run in worker process, CAN deliver task public function finish() { \Log::info(__CLASS__ . ':finish start', [$this->result]); Task::deliver(new TestTask2('task2 data')); // Deliver the other task } }
2. 发送任务。
// Create instance of TestTask and deliver it, "deliver" is asynchronous. use Hhxsv5\LaravelS\Swoole\Task\Task; $task = new TestTask('task data'); // $task->delay(3);// delay 3 seconds to deliver task $ret = Task::deliver($task); var_dump($ret);// Return true if sucess, otherwise false
毫秒级定时任务
基于 Swoole 的毫秒级定时器 的 cron 作业包装器,替换
LinuxCrontab。
1. 创建 cron 作业类。
namespace App\Jobs\Timer; use Hhxsv5\LaravelS\Swoole\Timer\CronJob; class TestCronJob extends CronJob { protected $i = 0; // Declare constructor without parameters public function __construct() { } public function interval() { return 1000;// Run every 1000ms } public function isImmediate() { return false;// Whether to trigger `run` immediately after setting up } public function run() { \Log::info(__METHOD__, ['start', $this->i, microtime(true)]); // do something $this->i++; \Log::info(__METHOD__, ['end', $this->i, microtime(true)]); if ($this->i >= 10) { // run 10 times only \Log::info(__METHOD__, ['stop', $this->i, microtime(true)]); $this->stop(); // stop this cron job } // throw new \Exception('an exception');// all exceptions will be ignored, then record them into Swoole log, you need to try/catch them } }
2. 绑定cron任务。
// Bind cron jobs in file "config/laravels.php" [ // ... 'timer' => [ 'enable' => true, // Enable Timer 'jobs' => [ // the list of cron job // Enable LaravelScheduleJob to run `php artisan schedule:run` every 1 minute, replace Linux Crontab //\Hhxsv5\LaravelS\Illuminate\LaravelScheduleJob::class, \App\Jobs\Timer\TestCronJob::class, ], ], // ... ];
3. 注意:在构建服务器集群时,会启动多个定时器,因此您需要确保只启动一个定时器,以避免运行重复的任务。
在您的项目中获取swoole_server实例
/** * $swoole is the instance of `swoole_websocket_server` if enable WebSocket server, otherwise `\swoole_http_server` * @var \swoole_http_server|\swoole_websocket_server $swoole */ $swoole = app('swoole'); var_dump($swoole->stats());// Singleton
使用swoole_table
1. 定义swoole_table,支持多个。
所有定义的表将在Swoole启动前创建。
// in file "config/laravels.php" [ // ... 'swoole_tables' => [ // Scene:bind UserId & FD in WebSocket 'ws' => [// The Key is table name, will add suffix "Table" to avoid naming conficts. Here defined a table named "wsTable" 'size' => 102400,// The max size 'column' => [// Define the columns ['name' => 'value', 'type' => \swoole_table::TYPE_INT, 'size' => 8], ], ], //...Define the other tables ], // ... ];
2. 访问swoole_table:所有表实例都将绑定到swoole_server上,通过app('swoole')->xxxTable访问。
// Scene:bind UserId & FD in WebSocket public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request) { // var_dump(app('swoole') === $server);// The same instance $userId = mt_rand(1000, 10000); app('swoole')->wsTable->set('uid:' . $userId, ['value' => $request->fd]);// Bind map uid to fd app('swoole')->wsTable->set('fd:' . $request->fd, ['value' => $userId]);// Bind map fd to uid $server->push($request->fd, 'Welcome to LaravelS'); } public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame) { foreach (app('swoole')->wsTable as $key => $row) { if (strpos($key, 'uid:') === 0) { $server->push($row['value'], 'Broadcast: ' . date('Y-m-d H:i:s'));// Broadcast } } } public function onClose(\swoole_websocket_server $server, $fd, $reactorId) { $uid = app('swoole')->wsTable->get('fd:' . $fd); if ($uid !== false) { app('swoole')->wsTable->del('uid:' . $uid['value']); // Ubind uid map } app('swoole')->wsTable->del('fd:' . $fd);// Unbind fd map $server->push($fd, 'Goodbye'); }
多端口混合协议
有关更多信息,请参阅Swoole Server AddListener
为了使我们的主服务器支持更多协议,而不仅仅是Http和WebSocket,我们在LaravelS中引入了Swoole的多端口混合协议功能,并将其命名为Socket。现在,您可以在Laravel上轻松构建TCP/UDP应用程序。
- 创建socket处理器类,并扩展
Hhxsv5\LaravelS\Swoole\Socket\{TcpSocket|UdpSocket|Http|WebSocket}。
namespace App\Sockets; use Hhxsv5\LaravelS\Swoole\Socket\TcpSocket; class TestTcpSocket extends TcpSocket { public function onConnect(\swoole_server $server, $fd, $reactorId) { \Log::info('New TCP connection', [$fd]); $server->send($fd, 'Welcome to LaravelS.'); } public function onReceive(\swoole_server $server, $fd, $reactorId, $data) { \Log::info('Received data', [$fd, $data]); $server->send($fd, 'LaravelS: ' . $data); if ($data === "quit\r\n") { $server->send($fd, 'LaravelS: bye' . PHP_EOL); $server->close($fd); } } public function onClose(\swoole_server $server, $fd, $reactorId) { \Log::info('New TCP connection', [$fd]); $server->send($fd, 'Goodbye'); } }
这些Socket连接与您的HTTP/WebSocket连接共享相同的worker进程。因此,如果您想要传递任务、使用swoole_table,甚至是Laravel组件(如DB、Eloquent等),这根本不会成为问题。同时,您可以通过成员属性swoolePort直接访问swoole_server_port对象。
public function onReceive(\swoole_server $server, $fd, $reactorId, $data) { $port = $this->swoolePort; //There you go }
- 注册Socket。
// Edit `config/laravels.php` //... 'sockets' => [ [ 'host' => '127.0.0.1', 'port' => 5291, 'type' => SWOOLE_SOCK_TCP,// Socket type: SWOOLE_SOCK_TCP/SWOOLE_SOCK_UDP 'settings' => [// Swoole settings:https://www.swoole.co.uk/docs/modules/swoole-server-methods#swoole_server-addlistener 'open_eof_check' => true, 'package_eof' => "\r\n", ], 'handler' => \App\Sockets\TestTcpSocket::class, ], ],
对于TCP套接字,当Swoole的dispatch_mode为1/3时,onConnect和onClose事件将被阻塞,因此如果您想解除这两个事件的阻塞,请将dispatch_mode设置为2/4/5。
'swoole' => [ //... 'dispatch_mode' => 2, //... ];
- 测试。
-
TCP:
telnet 127.0.0.1 5291 -
UDP: [Linux]
echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
- 注册其他协议的示例。
- UDP
'sockets' => [ [ 'host' => '0.0.0.0', 'port' => 5292, 'type' => SWOOLE_SOCK_UDP, 'settings' => [ 'open_eof_check' => true, 'package_eof' => "\r\n", ], 'handler' => \App\Sockets\TestUdpSocket::class, ], ],
- Http
'sockets' => [ [ 'host' => '0.0.0.0', 'port' => 5293, 'type' => SWOOLE_SOCK_TCP, 'settings' => [ 'open_http_protocol' => true, ], 'handler' => \App\Sockets\TestHttp::class, ], ],
- WebSocket
'sockets' => [ [ 'host' => '0.0.0.0', 'port' => 5294, 'type' => SWOOLE_SOCK_TCP, 'settings' => [ 'open_http_protocol' => true, 'open_websocket_protocol' => true, ], 'handler' => \App\Sockets\TestWebSocket::class, ], ],
协程 MySQL
支持MySQL数据库的协程客户端。
1. 要求:Swoole>=4.0,Laravel>=5.1(稍后支持Lumen)。
2. 在文件config/database.php中将MySQL连接的driver改为sw-co-mysql。
'connections' => [ //... 'mysql-test' => [ //'driver' => 'mysql', 'driver' => 'sw-co-mysql', 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', 3306), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, ], //... ],
3. 在文件config/app.php中将providers中的Illuminate\Database\DatabaseServiceProvider::class替换为\Hhxsv5\LaravelS\Illuminate\Database\DatabaseServiceProvider::class。
'providers' => [ //... //Illuminate\Database\DatabaseServiceProvider::class,// Just annotate this line. \Hhxsv5\LaravelS\Illuminate\Database\DatabaseServiceProvider::class, //... ],
4. 现在,您只需像往常一样使用QueryBuilder和ORM。(Alpha阶段,可能会有一些错误,请给我们反馈)。
重要提示
-
单例问题-
在FPM模式下,单例实例将在每个请求中实例化和回收,请求开始=>实例化实例=>请求结束=>回收实例。
-
在Swoole Server下,所有单例实例都将保留在内存中,其生命周期与FPM不同,请求开始=>实例化实例=>请求结束=>不回收单例实例。因此,需要开发者在每个请求中维护单例实例的状态。
-
常见解决方案
-
通过
Middleware重置单例实例的状态。 -
重新注册
ServiceProvider,将XxxServiceProvider添加到文件laravels.php的register_providers中。这样可以在每个请求中重新初始化单例实例参考。
-
-
-
从
Illuminate\Http\Request对象获取请求的所有信息,与$_SERVER/$_ENV/$_GET/$_POST/$_FILES/$_COOKIE/$_REQUEST兼容,不能使用$_SESSION。
public function form(\Illuminate\Http\Request $request) { $name = $request->input('name'); $all = $request->all(); $sessionId = $request->cookie('sessionId'); $photo = $request->file('photo'); $rawContent = $request->getContent(); //... }
- 通过
Illuminate\Http\Response对象响应,与echo/vardump()/print_r()兼容,不能使用像header()/setcookie()/http_response_code()这样的函数。
public function json() { return response()->json(['time' => time()])->header('header1', 'value1')->withCookie('c1', 'v1'); }
- 各种
单例连接将是内存驻留的,建议启用持久连接。
- 数据库连接,它将在断开连接后立即自动重新连接。
// config/database.php //... 'connections' => [ 'my_conn' => [ 'driver' => 'mysql', 'host' => env('DB_MY_CONN_HOST', 'localhost'), 'port' => env('DB_MY_CONN_PORT', 3306), 'database' => env('DB_MY_CONN_DATABASE', 'forge'), 'username' => env('DB_MY_CONN_USERNAME', 'forge'), 'password' => env('DB_MY_CONN_PASSWORD', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => false, 'options' => [ // Enable persistent connection \PDO::ATTR_PERSISTENT => true, ], ], //... ], //...
- Redis连接,它
不会在断开连接后立即自动重连,并且会抛出关于丢失连接的异常,下次将重连。您需要在每次操作Redis之前确保SELECT DB正确。
// config/database.php 'redis' => [ 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, 'persistent' => true, // Enable persistent connection ], ], //...
-
您声明的
global和static变量需要手动销毁(重置)。 -
无限地将元素追加到
static/global变量中会导致内存泄漏。
// Some class class Test { public static $array = []; public static $string = ''; } // Controller public function test(Request $req) { // Memory leak Test::$array[] = $req->input('param1'); Test::$string .= $req->input('param2'); }
待办事项列表
-
MySQL/Redis的连接池。
-
包装MySQL(alpha阶段)/Redis/Http的协程客户端。