itxiao6 / laravel-s
🚀 LaravelS: speed up Laravel/Lumen by Swoole, let's fly.
Installs: 16
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 474
pkg:composer/itxiao6/laravel-s
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: 2025-10-27 19:40:09 UTC
README
_ _ _____
| | | |/ ____|
| | __ _ _ __ __ ___ _____| | (___
| | / _` | '__/ _` \ \ / / _ \ |\___ \
| |___| (_| | | | (_| |\ V / __/ |____) |
|______\__,_|_| \__,_| \_/ \___|_|_____/
🚀 Speed up Laravel/Lumen by
Swoole, let's fly.
Features
-
Built-in Http/WebSocket server
-
Memory resident
-
Gracefully reload
-
Automatically reload when code is modified
-
Support Laravel/Lumen both, good compatibility
-
Simple & Out of the box
Requirements
| Dependency | Requirement |
|---|---|
| PHP | >= 5.5.9 |
| Swoole | >= 1.7.19 The Newer The Better No longer support PHP5 since 2.0.12 |
| Laravel/Lumen | >= 5.1 |
| Gzip[optional] | zlib, be used to compress the HTTP response, check by ldconfig -p|grep libz |
| Inotify[optional] | inotify, be used to reload all worker processes when your code is modified, check by php --ri inotify |
Install
1.Require package via Composer(packagist).
# 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.Register service provider.
Laravel: inconfig/app.phpfile
'providers' => [ //... Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class, ],
Lumen: inbootstrap/app.phpfile
$app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);
3.Publish configuration.
Suggest that do publish after upgrade LaravelS every time
php artisan laravels publish
Special for Lumen: you DO NOT need to load this configuration manually in bootstrap/app.php file, LaravelS will load it automatically.
// Unnecessary to call configure() $app->configure('laravels');
4.Change config/laravels.php: listen_ip, listen_port, refer Settings.
Run demo
php artisan laravels {start|stop|restart|reload|publish}
| Command | Description |
|---|---|
start |
Start LaravelS, list the processes by ps -ef|grep laravels |
stop |
Stop LaravelS |
restart |
Restart LaravelS |
reload |
Reload all worker processes(Contain your business & Laravel/Lumen codes), exclude master/manger process |
publish |
Publish configuration file laravels.php into folder config |
Cooperate with Nginx (Recommended)
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; } }
Cooperate with 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>
Enable WebSocket server
The Listening address of WebSocket Sever is the same as Http Server.
1.Create WebSocket Handler class, and implement interface 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.Modify 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.Use swoole_table to bind FD & UserId, optional, Swoole Table Demo. Also you can use the other global storage services, like Redis/Memcached/MySQL, but be careful that FD will be possible conflicting between multiple Swoole Servers.
4.Cooperate with Nginx (Recommended)
Refer WebSocket Proxy
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; } }
Listen events
System events
Usually, you can reset/destroy some
global/staticvariables, or change the currentRequest/Responseobject.
laravels.received_requestAfter LaravelS parsedswoole_http_requesttoIlluminate\Http\Request, before Laravel's Kernel handles this request.
// 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_responseAfter Laravel's Kernel handled the request, before LaravelS parsesIlluminate\Http\Responsetoswoole_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 });
Customized asynchronous events
This feature depends on
AsyncTaskofSwoole, your need to setswoole.task_worker_numinconfig/laravels.phpfirstly. The performance of asynchronous event processing is influenced by number of Swoole task process, you need to set task_worker_num appropriately.
1.Create event class.
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.Create listener class.
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.
// 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.Fire event.
// 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
Asynchronous task queue
This feature depends on
AsyncTaskofSwoole, your need to setswoole.task_worker_numinconfig/laravels.phpfirstly. The performance of task processing is influenced by number of Swoole task process, you need to set task_worker_num appropriately.
1.Create task class.
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.Deliver task.
// 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
Millisecond cron job
Wrapper cron job base on Swoole's Millisecond Timer, replace
LinuxCrontab.
1.Create cron job class.
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.Bind cron job.
// 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.Note: it will launch multiple timers when build the server cluster, so you need to make sure that launch one timer only to avoid running repetitive task.
Get the instance of swoole_server in your project
/** * $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
Use swoole_table
1.Define swoole_table, support multiple.
All defined tables will be created before Swoole starting.
// 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.Access swoole_table: all table instances will be bound on swoole_server, access by 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'); }
Multi-port mixed protocol
For more information, please refer to Swoole Server AddListener
To make our main server support more protocols not just Http and WebSocket, we bring the feature multi-port mixed protocol of Swoole in LaravelS and name it Socket. Now, you can build TCP/UDP applications easily on top of Laravel.
- Create socket handler class, and extend
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'); } }
These Socket connections share the same worker processes with your HTTP/WebSocket connections. So it won't be a problem at all if you want to deliver tasks, use swoole_table, even Laravel components such as DB, Eloquent and so on.
At the same time, you can access swoole_server_port object directly by member property swoolePort.
public function onReceive(\swoole_server $server, $fd, $reactorId, $data) { $port = $this->swoolePort; //There you go }
- Register Sockets.
// 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, ], ],
For TCP socket, onConnect and onClose events will be blocked when dispatch_mode of Swoole is 1/3, so if you want to unblock these two events please set dispatch_mode to 2/4/5.
'swoole' => [ //... 'dispatch_mode' => 2, //... ];
- Test.
-
TCP:
telnet 127.0.0.1 5291 -
UDP: [Linux]
echo "Hello LaravelS" > /dev/udp/127.0.0.1/5292
- Register example of other protocols.
- 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, ], ],
Coroutine MySQL
Support coroutine client for MySQL database.
1.Requirements: Swoole>=4.0, Laravel>=5.1(Lumen will be supported later).
2.Change the driver of MySQL connection to sw-co-mysql in file config/database.php.
'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.Replace Illuminate\Database\DatabaseServiceProvider::class of providers to \Hhxsv5\LaravelS\Illuminate\Database\DatabaseServiceProvider::class in file config/app.php.
'providers' => [ //... //Illuminate\Database\DatabaseServiceProvider::class,// Just annotate this line. \Hhxsv5\LaravelS\Illuminate\Database\DatabaseServiceProvider::class, //... ],
4.Now, you just use QueryBuilder and ORM as usual. (Alpha stage, there should be some bugs, please give us your feedback).
Important notices
-
Singleton Issue-
Under FPM mode, singleton instances will be instantiated and recycled in every request, request start=>instantiate instance=>request end=>recycled instance.
-
Under Swoole Server, All singleton instances will be held in memory, different lifetime from FPM, request start=>instantiate instance=>request end=>do not recycle singleton instance. So need developer to maintain status of singleton instances in ervery request.
-
Common solutions:
-
Resetstatus of singleton instances byMiddleware. -
Re-register
ServiceProvider, addXxxServiceProviderintoregister_providersof filelaravels.php. So that reinitialize singleton instances in ervery request Refer.
-
-
-
Get all info of request from
Illuminate\Http\RequestObject, compatible with $_SERVER/$_ENV/$_GET/$_POST/$_FILES/$_COOKIE/$_REQUEST,CANNOT USE$_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(); //... }
- Respond by
Illuminate\Http\ResponseObject, compatible with echo/vardump()/print_r(),CANNOT USEfunctions like header()/setcookie()/http_response_code().
public function json() { return response()->json(['time' => time()])->header('header1', 'value1')->withCookie('c1', 'v1'); }
- The various
singleton connectionswill bememory resident, recommend to enablepersistent connection.
- Database connection, it
willreconnect automaticallyimmediatelyafter disconnect.
// 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 connection, it
won'treconnect automaticallyimmediatelyafter disconnect, and will throw an exception about lost connection, reconnect next time. You need to make sure thatSELECT DBcorrectly before operating Redis every time.
// 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,staticvariables which you declared are need to destroy(reset) manually. -
Infinitely appending element into
static/globalvariable will lead to memory leak.
// 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'); }
Todo list
-
Connection pool for MySQL/Redis.
-
Wrap coroutine clients for MySQL(alpha stage)/Redis/Http.