首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
30
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
138
篇与
的结果
2023-08-11
PHP异步非阻塞的实现方法
PHP异步非阻塞的实现方法前言由于PHP本身是一种单进程的语言,每次请求在apache都是一个进程,在Nginx和fastCGI里面每个请求时一个单独的worker线程,而且在各个服务器里面的请求都是阻塞的,所以有些大批量的复杂逻辑或文本处理会导致请求响应时间很长,这里我们就要考虑让PHP实现异步非阻塞的做法,已达到减少响应时间的目的。一、各种实现方法1、FastCGI的非阻塞方法:fastcgi_finish_request()在PHP5.3.3版本之后,不管是Nginx还是Apache服务器,只要运行在FastCGI模式下,均可使用该方法,官方解释的作用是冲刷(flush)所有响应的数据给客户端。boolean fastcgi_finish_request ( void )此函数冲刷(flush)所有响应的数据给客户端并结束请求。 这使得客户端结束连接后,需要大量时间运行的任务能够继续运行。用法:可以在读写大文件、循环更新数据库等不影响结果的操作之前,执行该函数,把结果返回给客户端,php会继续执行下面的逻辑而不影响客户端的响应时间。2、fsockopen()+stream_set_blocking()方法:fsockopen()方法可以打开一个网络连接或Unxi套接字连接,stream_set_blocking()方法可以为资源流设置非阻塞或者阻塞模式,使用fsockopen()打开一个网络连接或者一个Unix套接字连接,再用stream_set_blocking()设置资源成非阻塞模式请求,则该资源请求会是非阻塞的:bool stream_set_blocking ( resource $stream , int $mode )注:$mode=0则是非阻塞的,1则是阻塞的模式。用法:3、使用cURL执行异步请求:cURL除了我们通常使用的curl_init来初始化和发送post和get请求之外,还可以使用curl_multi_init()方法来实现异步请求,其原理是使用系统的select这个多路I/O复用机制来异步发送请求。通常的用法:异步用法:4、使用Gearman/Swoole等PHP异步扩展或框架5、使用缓存和队列通常复杂的处理逻辑,我们可以将参数推入队列,如redis或kafka的队列服务,开启一个消费进程去处理队列事务。如redis服务的list结构,在之前篇章有过说明。6、使用pcntl_fork()在PHP4.1.0版本之后都支持了该函数,使用前需要安装支持pcntl扩展并添加支持。官方文档:在当前进程当前位置产生分支(子进程),这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同说明:int pcntl_fork ( void )成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0;失败时,在父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。用法:二、优劣对比并发IO问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接Fork进程,到Worker进程池/线程池,到现在的异步IO、协程。阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。现在网络的日益发展,对响应时间和处理并发的要求越来越高,所以异步非阻塞的需求也越来越多,优点也显而易见:1、非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程,能及时返回响应,减少响应时间;2、高并发,同步阻塞IO模型的并发能力依赖于进程/线程数量,响应时间的下降可以带来更多的并发能力。当然,异步非阻塞又存在缺点:1、启动大量进程会带来额外的进程调度消耗。非阻塞模式下,如果大量线程已经返回响应而仍然在执行计算操作,会使CPU利用率不可控的增高;2、这种模型严重依赖进程的数量解决并发问题,一个客户端连接就需要占用一个进程,工作进程的数量有多少,并发处理能力就有多少。操作系统可以创建的进程数量是有限的;3、过多的异步和多线程模型会造成编码困难或线程混乱,如出现大量僵尸进程等。三、总结1、一般情况下,我们不赞成用异步回调的方式去做功能开发,传统的PHP同步方式实现功能和逻辑是最简单的,也是最佳的方案。像node.js这样到处callback,只是牺牲可维护性和开发效率;2、有些时候很适合用异步,比如FTP、聊天服务器,smtp,代理服务器等等此类以通信和读写磁盘为主,功能和业务逻辑其次的服务器程序;3、异步非阻塞和多线程模型推荐:(1)swoole框架:fpm里,通过swoole_client把url发送到swoole的server,swoole_server天然支持并行请求,把汇总的结果返回到fpm;这也是当下PHP最火的异步多线程框架,可以了解一下韩天峰的文章:http://rango.swoole.com/(2)recoil框架:https://github.com/recoilphp/recoil参考文章:1、http://rango.swoole.com/archives/5082、https://www.kancloud.cn/fage/swoole_extension/6914313、https://www.awaimai.com/660.html
2023年08月11日
21 阅读
0 评论
0 点赞
2023-08-11
php 路由实现类,基于fastroute
php 路由实现类,基于fastroute<?php /** * 核心路由查找器 */ use FastRoute\RouteCollector; use function FastRoute\simpleDispatcher; use function FastRoute\cachedDispatcher; class FastRoute { public function __construct() { /** @var object $dispatcher 导入配置中的路由规则 */ // $dispatcher = simpleDispatcher(function (RouteCollector $r) { $dispatcher = cachedDispatcher(function (RouteCollector $r) { foreach ($GLOBALS['routeConfig'] as $key => $value) { if ($key) { $r->addGroup($key, function (RouteCollector $r) use ($key, $value) { foreach ($value as $k => $v) { // 如果控制器配置项为空时,默认根据路由获取控制器 $r->addRoute($v[0], $v[1], substr($key, 1) . ucfirst(empty($v[2]) ? $v[2] = substr($v[1], 1) . 'Controller' : $v[2])); } }); } else { foreach ($value as $k => $v) { $r->addRoute($v[0], $v[1], substr($v[2], 0, 1) === '/' ? substr(empty($v[2]) ? $v[2] = substr($v[1], 1) . 'Controller' : $v[2], 1) : $v[2]); } } } } ,[ 'cacheFile' => BASE_PATH . '/cache/route/route.cache', /* required */ 'cacheDisabled' => DEBUG, /* optional, enabled by default */ ]); // 获取http传参方式和资源URI $httpMethod = $_SERVER['REQUEST_METHOD']; $uri = $_SERVER['REQUEST_URI']; // 将url中的get传参方式(?foo=bar)剥离并对URI进行解析 if (false !== $pos = strpos($uri, '?')) { $uri = substr($uri, 0, $pos); } $uri = rawurldecode($uri); $routeInfo = $dispatcher->dispatch($httpMethod, $uri); switch ($routeInfo[0]) { // 使用未定义格式路由 case FastRoute\Dispatcher::NOT_FOUND: if (!DEBUG) { error(404,'404'); } else { throw new \Whoops\Exception\ErrorException('未定义此路由或未在新建文件后使用composer dump-autoload'); } break; /** * 请求的HTTP⽅法与配置的不符合 * HTTP规范要求405 Method Not Allowed响应包含“Allow:”头, * 用以详细说明所请求资源的可用方法。 * 使用FastRoute的应用程序在返回405响应时, * 应使用数组的第二个元素添加此标头。 */ case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: $allowedMethods = $routeInfo[1]; header('HTTP/1.1 405 Method Not Allowed'); $allow = implode(',', $allowedMethods); header('Allow:' . $allow); $errorMsg = "请求方式非法,可使用的请求方式为: $allow"; if ($_SERVER['REQUEST_METHOD'] === 'GET') { error(405, $errorMsg); } else { exit($errorMsg); } break; // 正常 case FastRoute\Dispatcher::FOUND: $handler = $routeInfo[1]; $class = '\app\controllers\\' . ucfirst($handler); $vars = $routeInfo[2]; $action = ucfirst(isset($vars['action']) ? $vars['action'] : 'index'); unset($vars['action']); $_SESSION['route'] = [ 'class' => substr($handler, 0, strpos(strtolower($handler), 'controller')), 'action' => strtolower(substr($action, 6)) ]; // ... 调用$handler和$vars echo call_user_func_array([ new $class, $action ], $vars); break; } } }路由配置文件<?php /** * 路由配置文件 */ return [ [ // 指向首页 [ ['GET', 'POST'], '/', 'HomeController' ], [ ['GET', 'POST'], '/demo', 'DemoController' ], // 指向adminController [ 'GET', '/admin', '' ], // 指向错误页面 [ 'GET', '/error/{code:\d+}', 'demoController' ], [ 'GET', '/user[/{action}]', 'userController' ], /*['GET','/user/{id:\d+}/{name}','userController'],*/ ], // 后台路由 '/admin' => [ // 指向adminUserController [ 'GET', '/user', '' ] ] ];
2023年08月11日
28 阅读
0 评论
0 点赞
2023-08-11
laravel万能路由( 自动路由、动态路由)实现方法分享
laravel万能路由( 自动路由、动态路由)实现方法分享有了万能路由就不用一条一条添加路由了,很方便。如果你要用资源控制器做Restful接口,那还是要写资源路由的,注意,资源路由一定要写在最上面。Route::resource('photos', 'PhotoController');//资源路由要写在上面。//万能路由Route::group(['middleware'=>['web']],function (){Route::any("/{module}/{controller}/{action}",function ($module,$class,$action){ $class = "App\\Http\\Controllers\$module\\".ucfirst(strtolower($class)).'Controller'; if(class_exists($class)) { $ctrl = \App::make($class); return \App::call([$ctrl, $action]); } return abort(404); })->where([ 'module'=>'[0-9a-zA-Z]+','class' => '[0-9a-zA-Z]+', 'action' => '[0-9a-zA-Z]+']);});在你的控制器方法中获取参数要用(Request $request)public function index(Request $request){ $name = $request->input('name'); echo $name; }友好url:如果你想拥有http://www.laravel65.com/Haha/photo/index/id/22/tag/php 这样的友好url请使用以下Route::resource('photos', 'PhotoController');//资源路由要写在上面。Route::get('/', function () {return view('welcome');});//万能路由Route::group(['middleware'=>['web']],function (){Route::any("/{search}",function ($search){ $urls=explode('/',$search); $module=$urls[0] ?? 'Index'; $className=$urls[1] ?? 'Index'; $action=$urls[2] ?? 'Index'; $class ="App\\Http\\Controllers\$module\\".ucfirst(strtolower($className)).'Controller'; $ctrl = \App::make($class); return \App::call([$ctrl, $action],[$search]); // } return abort(404); })->where('search', '.*');});同时在你控制器的方法中使用$search参数接收参数public function index(Request $request,$search){ var_dump($search); $name = $request->input('id'); echo 'index' .$name; }
2023年08月11日
10 阅读
0 评论
0 点赞
2023-08-11
PHP实现简单RPC
PHP实现简单RPC1.什么是rpcRPC全称为Remote Procedure Call,翻译过来为“远程过程调用”。目前,主流的平台中都支持各种远程调用技术,以满足分布式系统架构中不同的系统之间的远程通信和相互调用。远程调用的应用场景极其广泛,实现的方式也各式各样。2.从通信协议的层面基于HTTP协议的(例如基于文本的SOAP(XML)、Rest(JSON),基于二进制Hessian(Binary))基于TCP协议的(通常会借助Mina、Netty等高性能网络框架)3.从不同的开发语言和平台层面单种语言或平台特定支持的通信技术(例如Java平台的RMI、.NET平台Remoting)支持跨平台通信的技术(例如HTTP Rest、Thrift等)4.从调用过程来看同步通信调用(同步RPC)异步通信调用(MQ、异步RPC)5.常见的几种通信方式远程数据共享(例如:共享远程文件,共享数据库等实现不同系统通信)消息队列RPC(远程过程调用)6.php实现简单的rpc目录结构image.pngrpc服务端<?php/**User: yuzhaoCreateTime: 2018/11/15 下午11:46Description: Rpc服务端 */class RpcServer {/** * User: yuzhao * CreateTime: 2018/11/15 下午11:51 * @var array * Description: 此类的基本配置 */ private $params = [ 'host' => '', // ip地址,列出来的目的是为了友好看出来此变量中存储的信息 'port' => '', // 端口 'path' => '' // 服务目录 ]; /** * User: yuzhao * CreateTime: 2018/11/16 上午12:14 * @var array * Description: 本类常用配置 */ private $config = [ 'real_path' => '', 'max_size' => 2048 // 最大接收数据大小 ]; /** * User: yuzhao * CreateTime: 2018/11/15 下午11:50 * @var nul * Description: */ private $server = null; /** * Rpc constructor. */ public function __construct($params) { $this->check(); $this->init($params); } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:0 * Description: 必要验证 */ private function check() { $this->serverPath(); } /** * User: yuzhao * CreateTime: 2018/11/15 下午11:48 * Description: 初始化必要参数 */ private function init($params) { // 将传递过来的参数初始化 $this->params = $params; // 创建tcpsocket服务 $this->createServer(); } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:0 * Description: 创建tcpsocket服务 */ private function createServer() { $this->server = stream_socket_server("tcp://{$this->params['host']}:{$this->params['port']}", $errno,$errstr); if (!$this->server) exit([ $errno,$errstr ]); } /** * User: yuzhao * CreateTime: 2018/11/15 下午11:57 * Description: rpc服务目录 */ public function serverPath() { $path = $this->params['path']; $realPath = realpath(__DIR__ . $path); if ($realPath === false ||!file_exists($realPath)) { exit("{$path} error!"); } $this->config['real_path'] = $realPath; } /** * User: yuzhao * CreateTime: 2018/11/15 下午11:51 * Description: 返回当前对象 */ public static function instance($params) { return new RpcServer($params); } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:06 * Description: 运行 */ public function run() { while (true) { $client = stream_socket_accept($this->server); if ($client) { echo "有新连接\n"; $buf = fread($client, $this->config['max_size']); print_r('接收到的原始数据:'.$buf."\n"); // 自定义协议目的是拿到类方法和参数(可改成自己定义的) $this->parseProtocol($buf,$class, $method,$params); // 执行方法 $this->execMethod($client, $class, $method, $params); //关闭客户端 fclose($client); echo "关闭了连接\n"; } } } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:19 * @param $class * @param $method * @param $params * Description: 执行方法 */ private function execMethod($client, $class, $method, $params) { if($class && $method) { // 首字母转为大写 $class = ucfirst($class); $file = $this->params['path'] . '/' . $class . '.php'; //判断文件是否存在,如果有,则引入文件 if(file_exists($file)) { require_once $file; //实例化类,并调用客户端指定的方法 $obj = new $class(); //如果有参数,则传入指定参数 if(!$params) { $data = $obj->$method(); } else { $data = $obj->$method($params); } // 打包数据 $this->packProtocol($data); //把运行后的结果返回给客户端 fwrite($client, $data); } } else { fwrite($client, 'class or method error'); } } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:10 * Description: 解析协议 */ private function parseProtocol($buf, &$class, &$method, &$params) { $buf = json_decode($buf, true); $class = $buf['class']; $method = $buf['method']; $params = $buf['params']; } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:30 * @param $data * Description: 打包协议 */ private function packProtocol(&$data) { $data = json_encode($data, JSON_UNESCAPED_UNICODE); } }RpcServer::instance(['host' => '127.0.0.1', 'port' => 8888, 'path' => './api'])->run();rpc 客户端<?php/**User: yuzhaoCreateTime: 2018/11/16 上午12:2Description: Rpc客户端 */class RpcClient {/** * User: yuzhao * CreateTime: 2018/11/16 上午12:21 * @var array * Description: 调用的地址 */ private $urlInfo = array(); /** * RpcClient constructor. */ public function __construct($url) { $this->urlInfo = parse_url($url); } /** * User: yuzhao * CreateTime: 2018/11/16 上午12:2 * Description: 返回当前对象 */ public static function instance($url) { return new RpcClient($url); } public function __call($name, $arguments) { // TODO: Implement __call() method. //创建一个客户端 $client = stream_socket_client("tcp://{$this->urlInfo['host']}:{$this->urlInfo['port']}", $errno, $errstr); if (!$client) { exit("{$errno} : {$errstr} \n"); } $data = [ 'class' => basename($this->urlInfo['path']), 'method' => $name, 'params' => $arguments ]; //向服务端发送我们自定义的协议数据 fwrite($client, json_encode($data)); //读取服务端传来的数据 $data = fread($client, 2048); //关闭客户端 fclose($client); return $data; }}$cli = new RpcClient('http://127.0.0.1:8888/test');echo $cli->tuzisir1()."\n";echo $cli->tuzisir2(array('name' => 'tuzisir', 'age' => 23));提供服务的文件<?php/**User: yuzhaoCreateTime: 2018/11/16 上午12:28Description: */class Test {public function tuzisir1() { return '我是无参方法'; } public function tuzisir2($params) { return $params; }}效果image.png7.RPC的注意事项性能:影响RPC性能的主要在几个方面:1.序列化/反序列化的框架2.网络协议,网络模型,线程模型等安全RPC安全的主要在于服务接口的鉴权和访问控制支持。跨平台跨不同的操作系统,不同的编程语言和平台。
2023年08月11日
17 阅读
0 评论
0 点赞
2023-08-11
PHP里如何获取函数的调用位置
PHP里如何获取函数的调用位置<?php function c() { a(); } function a() { b(); } function b() { $backtrace = debug_backtrace(); $aa= array_shift($backtrace); var_dump($aa); } c(); /* 输出 array(4) { ["file"]=> string(14) "/code/main.php" ["line"]=> int(6) ["function"]=> string(1) "b" ["args"]=> array(0) { } } */ ?>
2023年08月11日
19 阅读
0 评论
0 点赞
1
...
18
19
20
...
28