首页
关于
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
篇文章
累计收到
28
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
100
篇与
的结果
2023-08-09
php实现SESSION跨域
php实现SESSION跨域稍微大一点的网站,通常都会有不只一个服务器,每个服务器运行着不同的功能模块或者不同的子系统,他们使用不同的二级域名,比如www.a.com、 i.a.com、bbs.a.com。而一个整体性强的网站,用户系统是统一的,即一套用户名、密码在整个网站的各个子系统中都是可以登录使用的。各个服 务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可。但还存在一个问题,就是用户在 i.a.com登录之后,进入www.a.com时,仍然需要重新登录,基本的通行证的问题,映射到技术上,其实就是各个服务器之间如何实现共享 SESSION 数据的问题。为了解决这个问题,我们采用将 SESSION 的数据保存数据库的方式。关于PHP SESSION的扫盲这里就不在累赘。在默认情况下,各个服务器会各自分别对同一个客户端产生 SESSION ID,如对于同一个用户浏览器,www.a.com系统产生的session id是a0211e9de3192ba6c22992d27a1b6a0a,而i.a.com生成的则是 277003f262f0c366946a86a28ba431d8。另外,PHP 的 SESSION 数据都是分别保存在本服务器的文件系统中。想要共享 SESSION 数据,那就必须实现两个目标:www.a.com和i.a.com所产生的SESSION ID相同,并且可通过同一个 COOKIE 进行传递,也就是说各个服务器必须可以读取同一个名为 PHPSESSID 的 COOKIE;另一个是 SESSION 数据必须存放在一个各个系统都能访问到的地方。简单地说就是多服务器共享客户端的 SESSION ID,同时还必须共享服务器端的 SESSION 数据。第一个目标的实现其实很简单,只需要对 COOKIE 的域(domain)进行特殊地设置即可,默认情况下,COOKIE 的域是当前服务器的域名/IP 地址,而域不同的话,各个服务器所设置的 COOKIE 是不能相互访问的,如 www.a.com 的服务器是不能读写 www.b.com 服务器设置的 COOKIE 的。这里我们所说的同一网站的服务器有其特殊性,那就是他们同属于同一个一级域,如:www.a.com 和 i.a.com 都属于域 .a.com,那么我们就可以设置 COOKIE 的域为 .a.com,这样 www.a.com、i.aaa.com 等等都可以访问此 COOKIE。PHP 代码中的设置方法如下:1 ini_set('session.cookie_domain', '.a.com');这样各个系统共享同一客户端 SESSION ID 的目的就达到了,下面就是共享SESSION数据,我们就将SESSION数据放在数据库中,首先建立数据库表:1 CREATE TABLE sessions (2 session_id varchar(32) NOT NULL,3 session_last_access int(10) unsigned,4 session_data text,5 PRIMARY KEY (session_id)session_id为主键,保存SESSION ID ,session_last_access是SESSION最后更新时间,session_data是SESSION数据。PHP 提供了session_set_save_handle() 函数,可以用此函数自定义 SESSION 的处理过程,当然首先要先将 session.save_handler 改成 user,可在 PHP 中进行设置:接下来着重讲一下 session_set_save_handle() 函数,此函数有六个参数:session_set_save_handler ( string open, string close, string read, string write, string destroy, string gc )各个参数为各项操作的函数名,这些操作依次是:打开、关闭、读取、写入、销毁、垃圾回收。
2023年08月09日
12 阅读
0 评论
0 点赞
2023-08-09
PHP设计模式
PHP设计模式阅读文档
2023年08月09日
18 阅读
0 评论
0 点赞
2023-08-09
结合Composer 新版本PHP的开发方式
结合Composer 新版本PHP的开发方式一、PHP的一些臭历史Dependency Manager For PHP,Composer。在Composer还没诞生之前,PHP的代码很难被管理。虽然pear社区的支持,许多可重用代码可以通过pear来获得,但是pear在处理代码关联性上非常差,当然还有许多问题。Java领域有Maven工具, .Net 的VS工具集成了NuGet,都是非常好使的关联管理器。但是PHP何去何从?Composer诞生了。它的诞生很大意义上是因为php的3.0版本被普及了,php的命名空间特性让代码包可以在全球级别上具备唯一识别性。当然有人说,我们可以在一个类的命名上做文章也可以做到,但是,会带来许多问题,类名太长,命名重名性高,文件的组织性识别性差等等。PHP根本无法忽略java,.net一直在被使用的package与命名空间的特性,php必须换血。随着php3.0的普及,通过众多第三方的努力,PHP社区迅猛的积累了许多可用的代码库,起初,大部分代码库都是分享在Github,采用git的方式获取。虽然这个可取,但是关联管理以及操作性上还是比较差。我们需要一个更加简单的具备关联管理的代码库管理工具。Yeah。Composer。好了,说到这里,或许许多人还很模糊。没关系,我们采用尝试动手,来熟悉Composer。二、初体验ComposerComposer具体点是什么? 就是一个编译压缩过的phar文件,一个可以执行的工具。怎么获取?Linux下$ curl -sS https://getcomposer.org/installer | phpwindows下C:\Users\username>cd C:\binC:\bin>php -r "readfile('https://getcomposer.org/installer');" | php完了,你可以在控制台下,输入命令 php composer.phar 来获取composer的使用帮助。下面我们来演示一下,如何使用Composer来创建一个PHP项目首先,创建一个项目目录ComposerDemo进入目录之后,使用以上命令来获取composer.phar,当然composer是可以全局配置,意思为不需要一个php项目下载一个Composer,而是共用一个Composer接下来 调用 php composer.phar init 可以自动创建一个 composer.json文件,当然你也可以手工创建。{"name": "kendoctor/composer_demo", "description": "introduction for how to use composer", "minimum-stability": "stable", "authors": [ { "name": "kendoctor", "email": "kendoctor@163.com" } ], "require": { }}这个文件很重要,它告诉composer如何工作。初始创建的模版,你可以修正一些你的项目的信息。name ,项目名称,命名规则,vendor名称/项目名称description,项目描述minium-stability,版本类型,具体内容参考官方阐述。这里先不作探讨。authors,作者信息。require, 这里可以请求你项目其他的相关php类库或类库包下面我们来演示Composer的第一个特性,类的自动载入首先,按照目录结构来创建文件ComposerDemo/├── composer.phar├── composer.json├── src/│ ├── models│ ├── Calculator.php├── index.php文件Calculator.php<?php/**Created by JetBrains PhpStorm.User: KendoctorDate: 14-3-19Time: 上午9:39To change this template use File | Settings | File Templates. */class Calculator {public function addNumbers($x,$y) { return $x + $y; }}我们要使用类Calculator,php老办法就是require这个类文件。事实上,我们在代码中会调用许多类,而这些类都会放到不同的文件中,那样的话,我们需要许多的require。我们知道index.php可以这么写<?php/**Created by JetBrains PhpStorm.User: kendoctorDate: 14-3-19Time: 上午9:40To change this template use File | Settings | File Templates. */require("src/models/Calculator.php");$calc = new Calculator();echo $calc->addNumbers(10,21);但是,这不是我们用了Composer想要的。我们要的效果是,实例某个类,它会自动载入。那,怎么搞呢?修改Composer.json{"name": "kendoctor/composer_demo", "description": "description_text", "minimum-stability": "stable", "authors": [ { "name": "author's name", "email": "email@example.com" } ], "autoload":{ "classmap": ["src/"] } }require这个属性被我删除了,稍等我们再来介绍其特性。首先这里引入一个autoload属性,可以自动加载类或命名空间的特性属性。classmap属性定义要引入的哪个目录下的类,或者直接可以是类文件。我们这里指定src目录下所有的类文件。修改之后,我们要通过composer命令来更新一下目录结构内容,很简单php composer.php dump-autoload完了会自动产生目录vendor,里面许多自动产生的内容,不过这里,我们只需要关注autoload.php这个文件。我们在index.php只需要引入这个文件就可以了<?php/**Created by JetBrains PhpStorm.User: kendoctorDate: 14-3-19Time: 上午9:40To change this template use File | Settings | File Templates. */require("vendor/autoload.php");$calc = new Calculator();echo $calc->addNumbers(10,21);如果你又新添加了一个User到models目录下,那你无需要做其他工作,就可以直接在index.php文件中直接调用此类了。
2023年08月09日
9 阅读
0 评论
0 点赞
2023-08-09
Composer概述及其自动加载探秘
Composer概述及其自动加载探秘composer概述一开始,最吸引我的当属 Composer 了,因为之前从没用过 Composer 。Composer 是PHP中用来管理依赖关系的工具,你只需在自己的项目中声明所依赖的外部工具库,Composer就会帮你安装这些依赖的库文件。运行 Composer 需要 PHP 5.3.2+ 以上版本。使用composer第一步,声明依赖关系。比方说,你正在创建的一个项目需要一个库来做日志记录。你决定使用 monolog。为了将它添加到你的项目中,你所需要做的就是创建一个 composer.json 文件,其中描述了项目的依赖关系。{"require": { "monolog/monolog": "1.2.*" }}第二步,使用composer。在项目根目录,执行安装命令,执行完毕后,monolog就会被下载到vendor/monolog/monolog 目录。$ php composer.phar install第三步,类的自动加载。除了库的下载,Composer 还准备了一个自动加载文件,它可以加载 Composer 下载的库中所有的类文件。使用它,你只需要将下面这行代码添加到你项目的引导文件中:require 'vendor/autoload.php';这使得你可以很容易的使用第三方代码。例如:如果你的项目依赖 monolog,你就可以像这样开始使用这个类库,并且他们将被自动加载。$log = new Monolog\Logger('name');$log->pushHandler(new Monolog\Handler\StreamHandler('app.log', Monolog\Logger::WARNING));$log->addWarning('Foo');Composer 自动加载探秘在现实世界中使用工具时,如果理解了工具的工作原理,使用起来就会更加有底气。对于一个第一次接触laravel,且是第一次接触 composer 的新手来说,如果理解Composer 是如何工作的,使用起来将会更加自如。我的理解是,composer 根据声明的依赖关系,从相关库的 源 下载代码文件,并根据依赖关系在 Composer 目录下生成供类自动加载的 PHP 脚本,使用的时候,项目开始处引入 “/vendor/autoload.php” 文件,就可以直接实例化这些第三方类库中的类了。那么,Composer 是如何实现类的自动加载的呢?接下来,我们从 laravel 的入口文件开始顺藤摸瓜往里跟进,来一睹 Composer 自动加载的奥妙。1.代码清单 laravel/public/index.php复制代码laravel/public/index.phprequire __DIR__.'/../bootstrap/autoload.php';$app = require_once __DIR__.'/../bootstrap/start.php';$app->run();复制代码第一行先是引入了 laravel/bootstrap/autoload.php,不做解释,打开该文件。2.代码清单 laravel/bootstrap/autoload.php复制代码define('LARAVEL_START', microtime(true));require __DIR__.'/../vendor/autoload.php';if (file_exists($compiled = __DIR__.'/compiled.php')){require $compiled;}Patchwork\Utf8\Bootup::initMbstring();复制代码第一行定义了程序开始执行的时间点。紧接着第二行,引入了 laravel/vendor/autoload.php。第七行,前面说过,引入Composer的autoload.php之后就可以直接使用第三方类库中的类了,这里就是直接使用的 Bootup 类。下面来看看 /vendor/autoload.php 到底做了什么。3.代码清单 laravel/vendor/autoload.php1 // autoload.php @generated by Composer2 3 require_once DIR . '/composer' . '/autoload_real.php';4 5 return ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256::getLoader();到这里,马上就进入自动加在的大门了。这个文件很简单,第5行的函数名是不是看的一头雾水?别被吓到了,他就是个类名而已。这个类是在第3行引入的文件 laravel/vendor/composer/autoload_real.php 里头声明的,接下来打开该文件看 getLoader();4.代码清单laravel/vendor/composer/autoload_real.php复制代码 1 <?php 2 3 // autoload_real.php @generated by Composer 4 5 class ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256 6 { 7 private static $loader; 8 9 public static function loadClassLoader($class)10 {11 if ('Composer\Autoload\ClassLoader' === $class) {12 require DIR . '/ClassLoader.php';13 }14 }15 16 17 public static function getLoader()18 {19 if (null !== self::$loader) {20 return self::$loader;21 }22 23 spl_autoload_register(array('ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256', 'loadClassLoader'), true, true);24 self::$loader = $loader = new \Composer\Autoload\ClassLoader();25 spl_autoload_unregister(array('ComposerAutoloaderInit9b2a1b1cf01c9a870ab98748dc5f1256', 'loadClassLoader'));26 27 $vendorDir = dirname(__DIR__); 28 $baseDir = dirname($vendorDir);29 30 $includePaths = require DIR . '/include_paths.php'; 31 32 array_push($includePaths, get_include_path());33 set_include_path(join(PATH_SEPARATOR, $includePaths));34 35 36 $map = require DIR . '/autoload_namespaces.php';37 foreach ($map as $namespace => $path) {38 $loader->set($namespace, $path);39 }40 41 $map = require DIR . '/autoload_psr4.php';42 foreach ($map as $namespace => $path) {43 $loader->setPsr4($namespace, $path);44 }45 46 $classMap = require DIR . '/autoload_classmap.php';47 if ($classMap) {48 $loader->addClassMap($classMap);49 }50 51 52 $loader->register(true);53 54 $includeFiles = require DIR . '/autoload_files.php';55 foreach ($includeFiles as $file) {56 composerRequire9b2a1b1cf01c9a870ab98748dc5f1256($file);57 }58 59 return $loader;60 }61 }62 63 function composerRequire9b2a1b1cf01c9a870ab98748dc5f1256($file)及 $loader->addClassMap()64 {65 require $file;66 }复制代码第17行,getLoader()中先是判断当前类中的 $loader 值,如果不是 null 就返回,这个可以略过。接着实例化了 ClassLoader 类给 $loader ,laravel/vendor/composer/ClassLoader.php这里引入了几个文件,这些文件是由composer自动生成的,当依赖关系发生改变时不需要修改这些脚本,运行composer重新生成即可。laravel/vendor/composer/autoloade_namespace.phplaravel/vendor/composer/autoloade_prs4.phplaravel/vendor/composer/autoloade_classmap.phplaravel/vendor/composer/autoloade_files.php在设置完一堆的 path 信息后,执行了$loader->set()和 $loader->setPsr4()及$loader->addClassMap(),然后 进行了$loader->register(true);现在我们一个个来看。5.代码清单laravel/vendor/composer/ClassLoader.phpView Code$loader->set($namespace, $path);Psr0标准设置命名空间对应的路径,以便于随后自动加载相关类文件。$loader->setPsr4($namespace, $path);Psr4标准设置命名空间对应的路径,以便于随后自动加载相关类文件。$loader->addClassMap($classMap);设置类文件路径与类名的对应关系,以便于随后自动加载相关类文件。$loader->register(true);public function register($prepend = false){spl_autoload_register(array($this, 'loadClass'), true, $prepend);}这里设置了 欲注册的自动装载函数 $this->loadClass(),关于 spl_autoload_register和 spl_autoload_unregister 的更多信息随后会有专门的解释。现在打开loadClass()的定义复制代码public function loadClass($class){if ($file = $this->findFile($class)) { includeFile($file); return true; }}复制代码这里有个 findFile() 函数,如果相关类的声明所在文件的路径找到了,就包含并运行该文件,然后返回 true 。接着打开findFile()的定义复制代码public function findFile($class){// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 if ('\\' == $class[0]) { $class = substr($class, 1); } // class map lookup if (isset($this->classMap[$class])) { return $this->classMap[$class]; } $file = $this->findFileWithExtension($class, '.php'); // Search for Hack files if we are running on HHVM if ($file === null && defined('HHVM_VERSION')) { $file = $this->findFileWithExtension($class, '.hh'); } if ($file === null) { // Remember that this class does not exist. return $this->classMap[$class] = false; } return $file;}复制代码先是判断类名是否以'\'开始,如果是的话,清除开头的'\'接着,检查当前类的名字是否在 类名与声明当前类的文件的路径的关系数组 中,如果存在,直接返回相关键值(类文件路径信息)如果上一步没有返回路径信息,执行 findFileWithExtension($class, '.php') 继续查找类文件路径信息,findFileWithExtension的定义后面将会列出。如果仍未找到类的文件路径信息,返回值为 null 且定义了 HHVM_VERSION 信息,则用“.hh”后缀继续查找类文件信息。HHVM_VERSION 是 HHVM版本信息? HHVM 是 Facebook 开发的高性能 PHP 虚拟机,宣称比官方的快9倍。如果仍未找到,则返回 false 。Remember that this class does not exist.(这句注释很有喜感?哈哈)代码清单 findFileWithExtension()复制代码 1 private function findFileWithExtension($class, $ext) 2 { 3 // PSR-4 lookup 4 $logicalPathPsr4 = strtr($class, '\', DIRECTORY_SEPARATOR) . $ext; 5 6 $first = $class[0]; 7 if (isset($this->prefixLengthsPsr4[$first])) { 8 foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { 9 if (0 === strpos($class, $prefix)) {10 foreach ($this->prefixDirsPsr4[$prefix] as $dir) {11 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {12 return $file;13 }14 }15 }16 }17 }18 19 // PSR-4 fallback dirs20 foreach ($this->fallbackDirsPsr4 as $dir) {21 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {22 return $file;23 }24 }25 26 // PSR-0 lookup27 if (false !== $pos = strrpos($class, '\')) {28 // namespaced class name29 $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)30 . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);31 } else {32 // PEAR-like class name33 $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;34 }35 36 if (isset($this->prefixesPsr0[$first])) {37 foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {38 if (0 === strpos($class, $prefix)) {39 foreach ($dirs as $dir) {40 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {41 return $file;42 }43 }44 }45 }46 }47 48 // PSR-0 fallback dirs49 foreach ($this->fallbackDirsPsr0 as $dir) {50 if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {51 return $file;52 }53 }54 55 // PSR-0 include paths.56 if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {57 return $file;58 }59 }复制代码该函数唯一的目的就是根据刚才通过$loader->set($namespace, $path)和$loader->setPsr4($namespace, $path)方法设置的信息找出类文件的路径信息。接下来,我们回到代码清单laravel/vendor/composer/autoload_real.php ,为精简篇幅,这里只贴出片段(续上节的 $loader->register(true))。复制代码 $loader->register(true); $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { composerRequire9b2a1b1cf01c9a870ab98748dc5f1256($file); } return $loader; }}function composerRequire9b2a1b1cf01c9a870ab98748dc5f1256($file){require $file;}复制代码在经历了一番长途跋涉后,终于从 laravel/vendor/composer/ClassLoader.php 中出来了。继 $loader->register(true) 之后,又引入了laravel/vendor/composer/autoload_files.php,相比之下,这个文件要简单得多,只是个数组,列出了几个文件路径。复制代码// autoload_files.php @generated by Composer$vendorDir = dirname(dirname(__FILE__));$baseDir = dirname($vendorDir);return array($vendorDir . '/ircmaxell/password-compat/lib/password.php', $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php', $vendorDir . '/laravel/framework/src/Illuminate/Support/helpers.php',);复制代码接着就是用 composerRequire9b2a1b1cf01c9a870ab98748dc5f1256() 函数 包含并运行 这几个文件。这四个文件的具体信息,随后会专门写博文来认识。最后 , 返回 ClassLoader 类的实例 $loader 。现在在回到 代码清单 laravel/bootstrap/autoload.php 的第7行复制代码1 define('LARAVEL_START', microtime(true));2 require __DIR__.'/../vendor/autoload.php';3 if (file_exists($compiled = __DIR__.'/compiled.php'))4 {5 require $compiled;6 }7 Patchwork\Utf8\Bootup::initMbstring();复制代码注意这里第7行,之所以可以直接像 Patchwork\Utf8\Bootup::initMbstring() 这么使用而不需要手动required Bootup类文件,是因为 前面在ClassLoader中的register() 函数用 spl_autoload_register() 对Bootup类进行了注册。下面说一下 spl_autoload_register 。spl_autoload_register要使用 spl_autoload_register ,请保证你的PHP版本(PHP 5 >= 5.1.2)。www.php.net 对 spl_autoload_register 的解释如下:注册__autoload()函数,将函数注册到SPL __autoload函数栈中。如果该栈中的函数尚未激活,则激活它们。刚接触 PHP 的同学肯定觉得这个解释云里雾里的,看完依然不知道什么意思。要想理解这句话,首先要弄明白 __autoload() 是个什么东西。__autoload()__autoload 的作用是尝试加载未定义的类,可以通过定义这个函数来启用类的自动加载。下面举个例子:复制代码function __autoload($class){echo '尝试加载的类的名字是:'.$class;}$say= @ new say();复制代码上例会输出:"尝试加载的类的名字是 say "。由于最后一行引用了尚未定义的类 box ,所以 __autoload 函数将被执行。再看下面这段复制代码class say{public function __construct() { echo 'say 类存在,并说出了hello,所以 __autoload 函数不会执行。'; }}function __autoload($class){echo '尝试加载的类的名字是:'.$class;}$say= @ new say();复制代码这将会输出 : say 类存在,并说出了hello,所以 __autoload 函数不会执行。理解完 __autoload 就好办了,再看上面:“将函数注册到SPL __autoload函数栈中”,意思是我们可以自定义 尝试加载未定义的类时 使用的函数。现在返回代码片段spl_autoload_register(array($this, 'loadClass'), true, $prepend);这下是不是很明白了,当实例化一个类的时候,如果这个类没有定义,就执行 ClassLoader 类中的 loadClass 函数。loadClass 的定义前面我们说过了,就是找到声明相关类的文件,然后包含并运行该文件,随后加载相关类。至此,composer的自动加载机制学习完毕。
2023年08月09日
14 阅读
0 评论
0 点赞
2023-08-09
利用 Composer 一步一步构建自己的 PHP 框架
PHP 命名空间 解惑利用 Composer 一步一步构建自己的 PHP 框架(一)——基础准备利用 Composer 一步一步构建自己的 PHP 框架(二)——构建路由利用 Composer 一步一步构建自己的 PHP 框架(三)——设计 MVC利用 Composer 一步一步构建自己的 PHP 框架(四)——使用 ORM利用 Composer 完善自己的 PHP 框架(一)——视图装载利用 Composer 完善自己的 PHP 框架(二)——发送邮件【完结】利用 Composer 完善自己的 PHP 框架(三)——Redis 缓存
2023年08月09日
10 阅读
0 评论
0 点赞
1
...
14
15
16
...
20