首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
185 阅读
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
篇文章
累计收到
33
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
560
篇与
的结果
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中的const和define 定义常量的区别
最新PHP中的const和define 定义常量的区别常量是一个简单的标识符。在脚本执行期间该值不能改变(除了所谓的魔术常量,他们其实不是常量)。常量大小写敏感(php 7.4*)。通常常量标识符总是大写的。const 通常用于类成员变量的定义。define不可用于类成员变量的定义,可用于全局常量。const是在编译时定义, 不能在函数,循环及if条件中使用; 函数define() 定义的常量是在执行define()函数时定义的,因此可以在函数内、循环内、if语句内等函数能够被调用的任何地方使用define()函数定义常量。<?phpconst FOO='BAR';//有效的validdefine('FOO', 'BAR');// 有效的validif (1) {const FOO='BAR';//无效的invalid}if (1) {define('FOO', 'BAR');// 有效的valid}3 .const定义的常量时大小写敏感的,而define可通过第三个参数(为true表示大小写不敏感)来指定大小写是否敏感(php7.4被弃用)。例如:<?phpdefine('FOO', 'BAR', true); //不区分大小写的常量的声明已从php7.4被弃用。现在将其TRUE作为第三个参数传递 给define()会生成弃用警告。不建议使用不区分大小写的常量const BAR =123;echo BAR;echo FOO;// BARecho foo; // BARconst的常量命名只能用直白的文本,而define()允许你用任何表达式来对常量命名。这样我们就可以执行以下操作:for ($i = 0; $i < 32; ++$i) {define('BIT_'. $i, 1<< $i);}类常量可见性从 php7.4开始支持.class ConstDemo{const PUBLIC_CONST_A=1;public const PUBLIC_CONST_B=2;protected const PROTECTED_CONST=3;private const PRIVATE_CONST=4;}需要注意的一点是,const可以在class和interface当中使用定义类常量 ,而define是做不到这一点的,但define可以在类方法中使用:class Foo {const BAR=2; // 有效}class Baz {define('QUX', 2); // 无效public function foo(define('QUX', 2); // 有效)}const默认在当前的namespace下定义常量,而使用define则需要你写明整个namespace的完整路径:命名空间的示例namespace A\B\C;// 如果要定义常量 A\B\C\FOO:const FOO = 'BAR';define('A\B\C\FOO', 'BAR');namespace A{const A1 = 1; //处在命名空间A中define('A2', 2); //全局可调用define('A\A3', 3); //处在命名空间A中}namespace B{use const\A\A1;use const\A\A3;echo A1;echo A2; //全局调用echo A3;}
2023年08月11日
9 阅读
0 评论
0 点赞
2023-08-11
谈谈PHP中的匿名函数与闭包
谈谈PHP中的匿名函数与闭包<?php //匿名函数,说白了就是“没有名字的函数”,不多说。给一段代码可能更为明白: //例一,定义匿名函数并调用 $str='world'; $func=function ($str) { echo 'hello '.$str; }; $func($str);// 输出 hello world //例二,定义匿名函数,用use 引入变量并调用 $str='world'; $func=function () use ($str) { echo 'hello '.$str; }; $func();//输出 hello world //例三 //在函数中把匿名函数返回,并且调用它 function getPrintStrFunc() { $func = function ($str) { echo $str; }; return $func; } $printStrFunc = getPrintStrFunc(); $printStrFunc('some string'); // 例四 //把匿名函数当做参数传递,并且调用它,这里实现了先定义参数 ,再传入函数的效果(和普通的函数先定义函数,再传入参数调用相反) function callFunc($func) { $func('some string'); } $printStrFunc = function ($str) { echo $str; }; callFunc($printStrFunc); //也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉 callFunc(function ($str) { echo $str; }); // 匿名函数和普通函数最大的区别是在于,匿名函数可以作为一个具体的“值”赋予给变量或者对象属性,其次,由于匿名函数可以被定义在不同地方,使得他可以有效利用他所在的局域内的变量(或者说上下文中的变量)。下面例子中就是这样一种情况。 class foo { public function exec(Closure $callback) { echo $callback(); } } $name = 'nick'; (new foo)->exec(function () use ($name) { return 'hi, '. $name; }); // 输出: hi, nick // 我们可以看到,匿名函数使用了上下文中的变量$name。而实际上,这个匿名函数是在另一个地方被执行(是在foo类里面被执行的)。这样使得我们不必将变量name的值通过参数传递到类foo的exec方法中,而且可以减少在exec方法中不必要的处理逻辑,使得类更容易专注于自己的职责。 // 匿名函数的作用还有很多,要知道,函数定义的时候是不会执行的,除非被调用。上文中例子其实就是这样,我们可以看到,例子中,对$name变量的处理是在方法exec被调用后才发生,且利用了匿名函数被定义时的上下文中的变量。这种特性,我们可以利用来实现一个控制反转(IoC)容器。 /** * 一个简单的IoC容器 */ class Container { protected static $bindings; public static function bind($abstract, Closure $concrete) { static::$bindings[$abstract] = $concrete; } public static function make($abstract) { return call_user_func(static::$bindings[$abstract]); } } /** * 示例用的 talk 类 */ class talk { public function greet($target) { echo 'hi, ' . $target->getName(); } } /** * 示例用的 A 类 */ class A { public function getName() { return 'Nick'; } } /** * 示例用的 B 类 */ class B { public function getName() { return 'Amy'; } } // 以下代码是主要示例代码 // 创建一个talk类的实例 $talk = new talk; // 将A类绑定至容器,命名为foo Container::bind('foo', function () { return new A; }); // 将B类绑定至容器,命名为bar Container::bind('bar', function () { return new B; }); // 通过容器取出实例 $talk->greet(Container::make('foo')); // hi, Nick $talk->greet(Container::make('bar')); // hi, Amy // 上述例子中,只有在通过make方法获取实例的时候,实例才被创建,这样使得我们可以实现容器,我们依照这一特性,还可以更多的实现高级的特性如事件触发等。利用好匿名函数,可以让应用变得更加丰满。 //彩蛋 匿名函数还可以这样调用:) (function ($name) { echo 'My name is ' . $name; })('jack ma'); // 输出: My name is jack ma
2023年08月11日
12 阅读
0 评论
0 点赞
2023-08-11
laravel-admin安装使用
laravel-admin安装使用laravel-admin是一个超级棒的PHP后台框架,只用写极其少量的代码,就可以开发后台功能,不用写方法,不用创建与修改模板,开发速度是其它框架的N倍。堪称用最少的时间构建出功能完善的管理后台!!!安装方法:一.可参考(https://github.com/w3yyb/laravel-admin-skeleton,使用laravel 6)二.使用laravel 71.安装laravel 7.xcomposer create-project --prefer-dist laravel/laravel blog2.mysql新建数据库laraveladmin3.修改.env文件数据库信息DB_CONNECTION=mysqlDB_HOST=127.0.0.1DB_PORT=3306DB_DATABASE=laraveladminDB_USERNAME=rootDB_PASSWORD=××××××4.安装laravel-admincomposer require encore/laravel-adminphp artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"php artisan admin:install在config/filesystems.php中disks中添加admin:'disks'=> ['local'=> ['driver'=>'local','root'=>storage_path('app'),],'public'=> ['driver'=>'local','root'=>storage_path('app/public'),'url'=>env('APP_URL').'/storage','visibility'=>'public',],'s3'=> ['driver'=>'s3','key'=>env('AWS_ACCESS_KEY_ID'),'secret'=>env('AWS_SECRET_ACCESS_KEY'),'region'=>env('AWS_DEFAULT_REGION'),'bucket'=>env('AWS_BUCKET'),'url'=>env('AWS_URL'),'endpoint'=>env('AWS_ENDPOINT'),],'admin'=> ['driver'=>'local','root'=>public_path('upload'),'visibility'=>'public','url'=>env('APP_URL').'/upload/',],6.运行: php artisan serve打开路由:http://127.0.0.1:8000/admin认证:账号 admin,密码 adminhttp://www.dcatadmin.com/ 这个是 基于laravel-admin开发的,比laravel-admin更好,推荐使用。
2023年08月11日
12 阅读
0 评论
0 点赞
2023-08-11
laravel的RESTful实现:RESTful资源控制器-通过laravel 学习RESTful
laravel的RESTful实现:RESTful资源控制器-通过laravel 学习RESTfulRESTful 资源控制器资源控制器让你可以轻松地创建与资源相关的 RESTful 控制器.Laravel 的资源路由将典型的「CURD (增删改查)」路由分配给具有单行代码的控制器。例如,你希望创建一个控制器来处理保存 "照片" 应用的所有 HTTP 请求。使用 Artisan 命令 make:controller ,我们可以快速创建这样一个控制器:php artisan make:controller PhotoController --resource这个命令将会生成一个控制器 app/Http/Controllers/PhotoController.php 。其中包括每个可用资源操作的方法。接下来,你可以给控制器注册一个资源路由:Route::resource('photos', 'PhotoController');这个单一的路由声明创建了多个路由来处理资源上的各种行为。用来处理各式各样和相片资源相关的的 RESTful 行为.生成的控制器为每个行为保留了方法,包括了关于处理 HTTP 动词和 URLs 的声明注释。你可以通过将数组传参到 resources 方法中的方式来一次性的创建多个资源控制器:Route::resources(['photos' => 'PhotoController', 'posts' => 'PostController']);资源控制器操作处理HTTP 方法 URI 动作 含义 路由名称GET /photos index 查看photos列表 photos.indexGET /photos/create create 打开添加页面 photos.createPOST /photos store 添加保存 photos.storeGET /photos/{photo} show 查看详情 photos.showGET /photos/{photo}/edit edit 打开编辑页面 photos.editPUT/PATCH /photos/{photo} update 编辑保存 photos.updateDELETE /photos/{photo} destroy 删除一个photo photos.destroy注 PUT为全部更新,PATCH为部分更新。指定资源模型如果你使用了路由模型绑定,并且想在资源控制器的方法中使用类型提示,你可以在生成控制器的时候使用 --model 选项:php artisan make:controller PhotoController --resource --model=Photo伪造表单方法因为 HTML 的表单不能生成 PUT,PATCH,和 DELETE 请求,所以你需要添加一个隐藏的 _method 字段来伪造 HTTP 动作。这个 Blade 指令 @method 可以为你创造这个字段: @method('PUT') 部分资源路由当声明资源路由时,你可以指定控制器处理的部分行为,而不是所有默认的行为:Route::resource('photos', 'PhotoController')->only(['index', 'show']);Route::resource('photos', 'PhotoController')->except(['create', 'store', 'update', 'destroy']);API 资源路由当声明用于 APIs 的资源路由时,通常需要排除显示 HTML 模板的路由(如 create 和 edit )。为了方便起见,你可以使用 apiResource 方法自动排除这两个路由:Route::apiResource('photos', 'PhotoController');你可以传递一个数组给 apiResources 方法来同时注册多个 API 资源控制器:Route::apiResources(['photos' => 'PhotoController', 'posts' => 'PostController']);要快速生成不包含 create 或 edit 方法的用于开发接口的资源控制器,请在执行 make:controller 命令时使用 --api 开关:php artisan make:controller API/PhotoController --api命名资源路由默认情况下,所有的资源控制器行为都有一个路由名称。你可以传入 names 数组来覆盖这些名称:Route::resource('photos', 'PhotoController')->names(['create' => 'photos.build']);命名资源路由参数默认情况下,Route::resource 会根据资源名称的「单数」形式创建资源路由的路由参数。你可以在选项数组中传入 parameters 参数来轻松地覆盖每个资源。parameters 数组应该是资源名称和参数名称的关联数组:Route::resource('users', 'AdminUserController')->parameters(['users' => 'admin_user']);上例将会为资源的 show 路由生成如下的 URI :/users/{admin_user}本地化资源 URI默认情况下,Route::resource 将会用英文动词创建资源 URI。如果需要本地化 create 和 edit 行为动作名,可以在 AppServiceProvider 的 boot 中使用 Route::resourceVerbs 方法实现:use Illuminate\Support\Facades\Route;/**引导任何应用服务。 *@return void */public function boot(){Route::resourceVerbs([ 'create' => 'crear', 'edit' => 'editar', ]);}动作被自定义后,像 Route::resource('fotos', 'PhotoController') 这样注册的资源路由将会产生如下的 URI:/fotos/crear/fotos/{foto}/editar补充资源控制器如果你想在默认的资源路由中增加额外的路由,你应该在 Route::resource 之前定义这些路由。否则由 resource 方法定义的路由可能会无意中优先于你补充的路由:Route::get('photos/popular', 'PhotoController@method');Route::resource('photos', 'PhotoController');以上代码适用于laravel 6.x。
2023年08月11日
17 阅读
0 评论
0 点赞
1
...
51
52
53
...
112