首页
网站导航
关于
Search
1
解决Typecho Joe主题访问fastly.jsdelivr.net速度慢的方案 | 快速优化技巧
2,190 阅读
2
解决WSL2内存不释放问题的最佳指南
1,401 阅读
3
如何在 Typecho Joe 主题的文章中增加目录
1,170 阅读
4
GO语言环境的搭建教程 - 完全指南
1,004 阅读
5
如何解决Win11电脑桌面上方显示横线问题 | 窗口11教程
1,004 阅读
默认分类
编程语言
GO语言
PHP
Node
javascript
html
rust
java
Css
Python
资源分享
chrome插件
阅读思考
运维架构
redis
Nginx
linux
memcached
mongodb
mysql
windows
docker
k8s
Mq
apache
CI
Git
swoole
elk
系统设计
thinkPhp
beego
登录
Search
标签搜索
重要
go基础
git 命令
go包
phpstorm
sublime
thinkphp6
mysql问题
软件分享
redis命令
php基础
thinkphp3.2
php第三扩展包
小蚯蚓博客
累计撰写
333
篇文章
累计收到
48
条评论
首页
栏目
默认分类
编程语言
GO语言
PHP
Node
javascript
html
rust
java
Css
Python
资源分享
chrome插件
阅读思考
运维架构
redis
Nginx
linux
memcached
mongodb
mysql
windows
docker
k8s
Mq
apache
CI
Git
swoole
elk
系统设计
thinkPhp
beego
页面
网站导航
关于
搜索到
44
篇与
的结果
2024-04-05
解决安装php的zip扩展时遇到的问题 | 技术支持
当前环境 CentOS Linux release 7.6.1810 (Core) php 8.1.16 问题 前段时间在个人的服务器上想升级一下php版本,然后就下载编译安装了7.4.3版本。编译时遇到几个No package 'xxx' found,比如No package 'sqlite3' found,只需要网上搜一下安装对应的库就行了,比如对应sqlite3的,执行yum install sqlite-devel就可以了。这里不多赘述,网上搜一下就行了。 但是有个libzip提示版本太低,yum自带的是0.10,网上各种升级安装,源码编译安装都不好用,还是会有相同的提示。 checking whether to enable zend-test extension... no checking for zip archive read/write support... yes checking for libzip >= 0.11... no configure: error: Package requirements (libzip >= 0.11) were not met: Requested 'libzip >= 0.11' but version of libzip is 0.10.1 Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables LIBZIP_CFLAGS and LIBZIP_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. 解决 姿势一(方便) 这个方法经过验证,无效,所以还是用姿势二吧 rpm -Uvh http://rpms.remirepo.net/enterprise/remi-release-7.rpm yum —enablerepo=remi install libzip5-devel 姿势二(知道咋回事) 编译安装,指定PKG_CONFIG_PATH,上面报错中其实有提示信息,让我们考虑调整PKG_CONFIG_PATH环境变量。 下面是详细步骤: # 先卸载已有 yum remove libzip # 然后安装 wget https://libzip.org/download/libzip-1.2.0.tar.gz tar -zxvf libzip-1.2.0.tar.gz cd libzip-1.2.0 ./configure make && make install 装完了之后找一下/usr/local/lib下有没有pkgconfig目录,有的话执行命令export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig/"指定PKG_CONFIG_PATH。 到这里问题解决!
2024年04月05日
64 阅读
0 评论
0 点赞
2024-04-02
Windows下php安装扩展imagick 3.7.0
概述 ImageMagick 是用来创建,编辑,合并位图图像的一套组件。 它能够用于读取,转换,写入多种不同格式的图像。 包含 DPX、EXR、GIF、JPEG、JPEG-2000、PDF、PhotoCD、PNG、Postscript、SVG 和 TIFF。 window 下安装 下载链接如下: PHP 8.1 8.1 Non Thread Safe (NTS) x64 8.1 Thread Safe (TS) x64 8.1 Non Thread Safe (NTS) x86 8.1 Thread Safe (TS) x86 PHP 8.0 8.0 Non Thread Safe (NTS) x64 8.0 Thread Safe (TS) x64 8.0 Non Thread Safe (NTS) x86 8.0 Thread Safe (TS) x86 PHP 7.4 7.4 Non Thread Safe (NTS) x64 7.4 Thread Safe (TS) x64 7.4 Non Thread Safe (NTS) x86 7.4 Thread Safe (TS) x86 其他版本下载地址: http://pecl.php.net/package/imagick 安装imagick 解压文件夹后,将 php_imagick.dll 复制到php的ext文件夹; 将解压后的其他dll文件复制到php安装目录 改php.ini,加上extension=imagick; 新启动 Apache/NGINX Windows 服务。 或许php安装目录有点凌乱,也可以将上述第二步替换为:**将解压后的文件夹放到php安装目录**,这个方式试了下好像不行,还是按第二步吧 然后将目录添加到系统环境变量: 完了重新启动 Apache/NGINX Windows 服务 安装完成。 要测试扩展是否有效,您可以运行以下 PHP 代码: <?php $image = new Imagick(); $image->newImage(1, 1, new ImagickPixel('#ffffff')); $image->setImageFormat('png'); $pngData = $image->getImagesBlob(); echo strpos($pngData, "\x89PNG\r\n\x1a\n") === 0 ? 'Ok' : 'Failed'; linux 下安装 要安装依赖,其他的还是正常phpize安装 sudo yum install ImageMagick ImageMagick-devel
2024年04月02日
25 阅读
0 评论
0 点赞
2024-03-29
Laravel Artisan 使用: 最佳实践与技巧
系统命令使用 artisan 命令主要是控制台的命令,输入 php artisan 后输出 PS D:\project\php\strongshop> php artisan Laravel Framework 6.20.30 Usage: command [options] [arguments] Options: -h, --help Display this help message -q, --quiet Do not output any message -V, --version Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output -n, --no-interaction Do not ask any interactive question --env[=ENV] The environment the command should run under -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug Available commands: clear-compiled Remove the compiled class file down Put the application into maintenance mode env Display the current framework environment help Display help for a command list List commands migrate Run the database migrations optimize Cache the framework bootstrap files preset Swap the front-end scaffolding for the application serve Serve the application on the PHP development server tinker Interact with your application ui Swap the front-end scaffolding for the application up Bring the application out of maintenance mode auth auth:clear-resets Flush expired password reset tokens cache cache:clear Flush the application cache cache:forget Remove an item from the cache cache:table Create a migration for the cache database table config config:cache Create a cache file for faster configuration loading config:clear Remove the configuration cache file db db:seed Seed the database with records db:wipe Drop all tables, views, and types event event:cache Discover and cache the application's events and listeners event:clear Clear all cached events and listeners event:generate Generate the missing events and listeners based on registration event:list List the application's events and listeners key key:generate Set the application key make make:channel Create a new channel class make:command Create a new Artisan command make:controller Create a new controller class make:event Create a new event class make:exception Create a new custom exception class make:factory Create a new model factory make:job Create a new job class make:listener Create a new event listener class make:mail Create a new email class make:middleware Create a new middleware class make:migration Create a new migration file make:model Create a new Eloquent model class make:notification Create a new notification class make:observer Create a new observer class make:policy Create a new policy class make:provider Create a new service provider class make:request Create a new form request class make:resource Create a new resource make:rule Create a new validation rule make:seeder Create a new seeder class make:test Create a new test class migrate migrate:fresh Drop all tables and re-run all migrations migrate:install Create the migration repository migrate:refresh Reset and re-run all migrations migrate:reset Rollback all database migrations migrate:rollback Rollback the last database migration migrate:status Show the status of each migration notifications notifications:table Create a migration for the notifications table optimize optimize:clear Remove the cached bootstrap files package package:discover Rebuild the cached package manifest queue queue:failed List all of the failed queue jobs queue:failed-table Create a migration for the failed queue jobs database table queue:flush Flush all of the failed queue jobs queue:forget Delete a failed queue job queue:listen Listen to a given queue queue:restart Restart queue worker daemons after their current job queue:retry Retry a failed queue job queue:table Create a migration for the queue jobs database table queue:work Start processing jobs on the queue as a daemon route route:cache Create a route cache file for faster route registration route:clear Remove the route cache file route:list List all registered routes schedule schedule:run Run the scheduled commands scout scout:flush Flush all of the model's records from the index scout:import Import the given model into the search index session session:table Create a migration for the session database table storage storage:link Create a symbolic link from "public/storage" to "storage/app/public" telescope telescope:clear Clear all entries from Telescope telescope:install Install all of the Telescope resources telescope:prune Prune stale entries from the Telescope database telescope:publish Publish all of the Telescope resources ui ui:auth Scaffold basic login and registration views and routes vendor vendor:publish Publish any publishable assets from vendor packages view view:cache Compile all of the application's Blade templates view:clear Clear all compiled view files 查看所有命令 php artisan php aratisan list 每个命令都有个帮助 例如 php artisan help migrate 运行迁移 执行未执行过的迁移文件,如果已经执行过不会被执行 php artisan migrate 此命令将执行/database/migrations目录下的所有未执行的迁移文件,主要是执行文件里的up方法。并将记录插入Laravel迁移表中。laravel 里有个 前缀_migrations 的表来判断是否已经执行过了 Make 创建命令 生成控制器 要创建一个控制器,可以使用以下命令: php artisan make:controller UserController 其中UserController是控制器的名称。执行以上命令后,Laravel会在/app/Http/Controllers目录下生成一个UserController.php文件,该文件是一个空的控制器类。 生成模型 要创建一个模型,可以使用以下命令,laravel的model,没有Model后缀: php artisan make:model User 其中User是模型的名称。执行以上命令后,Laravel会在/app目录下生成一个User.php文件,该文件是一个空的模型类。 自动生成注释 php artisan ide-helper:models "App\Models\User" 记住一定要加引号 生成迁移 php artisan make:migration create_user_table --create=users 其中create_users_table是迁移文件的名称,--create=users表示要创建一个名为users的表。执行以上命令后,Laravel会在/database/migrations目录下生成一个迁移文件,该文件包含up()和down()两个方法,可以在其中添加创建和删除表的操作。 生成 seeder php artisan make:seeder UsersTableSeeder 其中UsersTableSeeder是Seeder的名称。执行以上命令后,Laravel会在/database/seeds目录下生成一个UsersTableSeeder.php文件,该文件是一个类,可以在其中添加插入数据的操作 生成命令 要创建新命令,可以使用 make:command Artisan 命令。该命令会在 app/Console/Commands 目录下创建一个新的命令类。如果该目录不存在,也无需担心 - 它会在第一次运行 make:command Artisan 命令的时候自动创建: php artisan make:command SendEmails db 相关的操作 运行Seeder php artisan db:seed 此命令将执行/database/seeds目录下的所有Seeder类,并将记录插入数据库中。试了下好像不行 注册command 类命令:在/app/Console/Commands目录下创建一个新的PHP类 闭包命令:routes/console.php 命令还有一种是单例命令,可以确保没用同时执行的命令。
2024年03月29日
43 阅读
0 评论
0 点赞
2023-11-26
在 CentOS 7 系统上安装 PHP 7.4 版本的详细步骤
添加 EPEL 和 REMI 存储库 运行以下命令以添加所需的存储库: sudo yum install epel-release sudo yum -y install https://rpms.remirepo.net/enterprise/remi-release-7.rpm 在 CentOS 7 上安装 PHP 7.4版本 我们现在可以启用 PHP 7.4 Remi 存储库并在 CentOS 7 上安装 PHP 7.4: sudo yum -y install yum-utils yum repolist all |grep php sudo yum-config-manager --enable remi-php74 在 CentOS 7 上安装 PHP 7.4 以及扩展: sudo yum install php php-cli php-fpm php-mysqlnd php-zip php-devel php-gd php-mcrypt php-mbstring php-curl php-xml php-pear php-bcmath php-json php-redis 当前的 PHP 版本应为 7.4 版,如下所示: php -v 如果要查看启用的模块,请运行: php --modules 至此,你已经在 CentOS 7 上成功安装了 PHP 7.4,欢迎使用此版本进行 PHP 开发/测试。
2023年11月26日
80 阅读
0 评论
0 点赞
2023-11-26
解决PHP组件编译安装错误:内存不足
背景 前面一篇我们介绍了宝塔面板的 PHP 默认不安装 fileinfo 组件,需要手动编译安装。在 php 5.6 上是没有出现问题,但是在编译 php 7.1 的版本的 make && make install 这一步出现错误,提示: virtual memory exhausted: Cannot allocate memory Makefile:197: recipe for target 'libmagic/apprentice.lo' failed 下面是 make 编译后的详细信息: /www/server/php/71/src/ext/fileinfo# make && make install /bin/sh /www/server/php/71/src/ext/fileinfo/libtool --mode=compile cc -I/www/server/php/71/src/ext/fileinfo/libmagic -I. -I/www/server/php/71/src/ext/fileinfo -DPHP_ATOM_INC -I/www/server/php/71/src/ext/fileinfo/include -I/www/server/php/71/src/ext/fileinfo/main -I/www/server/php/71/src/ext/fileinfo -I/www/server/php/71/include/php -I/www/server/php/71/include/php/main -I/www/server/php/71/include/php/TSRM -I/www/server/php/71/include/php/Zend -I/www/server/php/71/include/php/ext -I/www/server/php/71/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /www/server/php/71/src/ext/fileinfo/libmagic/apprentice.c -o libmagic/apprentice.lo cc -I/www/server/php/71/src/ext/fileinfo/libmagic -I. -I/www/server/php/71/src/ext/fileinfo -DPHP_ATOM_INC -I/www/server/php/71/src/ext/fileinfo/include -I/www/server/php/71/src/ext/fileinfo/main -I/www/server/php/71/src/ext/fileinfo -I/www/server/php/71/include/php -I/www/server/php/71/include/php/main -I/www/server/php/71/include/php/TSRM -I/www/server/php/71/include/php/Zend -I/www/server/php/71/include/php/ext -I/www/server/php/71/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /www/server/php/71/src/ext/fileinfo/libmagic/apprentice.c -fPIC -DPIC -o libmagic/.libs/apprentice.o virtual memory exhausted: Cannot allocate memory Makefile:197: recipe for target 'libmagic/apprentice.lo' failed make: *** [libmagic/apprentice.lo] Error 1 原因 这个意思是内存不足,无法完成编译。 本次使用的是 AWS t 2. micro 配置的 EC 2 实例,实际上其内存有 1 GB,但是还是出现本次的错误,应该是同时运行的其他程序导致内存不足。 解决办法 既然这样,物理内存不足我们没办法,但是可以通过自行增加虚拟内存的方法来解决。 通过 free -m 来查看下内存使用状况 # free -m total used free shared buff/cache available Mem: 990 466 447 3 76 401 Swap: 0 0 0 创建一个目录/opt/images/ 你可以自己定路径 # mkdir /opt/images/ # rm -rf /opt/images/swap 创建一个 2 GB 大小的文件 # dd if=/dev/zero of=/opt/images/swap bs=1024 count=2048000 2048000+0 records in 2048000+0 records out 2097152000 bytes (2.1 GB, 2.0 GiB) copied, 30.3635 s, 69.1 MB/s 把创建的文件变成 SWAP 分区 # mkswap /opt/images/swap Setting up swapspace version 1, size = 2 GiB (2097147904 bytes) no label, UUID=dd2fa2db-f8bd-41db-9e1a-5d9257924c6f 启用这个 SWAP 文件 # swapon /opt/images/swap swapon: /opt/images/swap: insecure permissions 0644, 0600 suggested. 看看 SWAP 是否生效 # free -m total used free shared buff/cache available Mem: 990 467 64 3 458 356 Swap: 1999 0 1999 可以看到的确有 2 GB 的 SWAP 内存 然后回到原来的作业 使用 cd - 回到原来的 /www/server/php/71/src/ext/fileinfo 目录 继续编译 fileinfo 执行成功 See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages. ---------------------------------------------------------------------- Build complete. Don't forget to run 'make test'. Installing shared extensions: /www/server/php/71/lib/php/extensions/no-debug-non-zts-20160303/ 完成后关闭 SWAP # swapoff /opt/images/swap # rm -f /opt/images/swap 以后再出现内存不足可以通过增加 SWAP 虚拟内存来解决~
2023年11月26日
139 阅读
0 评论
0 点赞
2022-10-18
PHP全局变量一站式服务 | 深入了解PHP全局变量使用方法
介绍 php中有很多全局变量,用于接收传入脚本的参数。 全局变量 $argv变量 用于接收命令行php命令行的参数,例如有脚本test.php,内容如下 <?php print_r($argv); echo "PHP命令的第1个参数:", current($argv),PHP_EOL; echo "PHP命令的第2个参数:", next($argv), PHP_EOL; echo "PHP命令的第3个参数:", next($argv), PHP_EOL; echo "PHP命令的第4个参数:", next($argv), PHP_EOL; echo "PHP命令的第5个参数:", next($argv), PHP_EOL; reset($argv); 执行php test.php输出结果 Array ( [0] => test.php [1] => a [2] => b [3] => c ) PHP命令的第1个参数:test.php PHP命令的第2个参数:a PHP命令的第3个参数:b PHP命令的第4个参数:c PHP命令的第5个参数: 当php运行在cli模式的是,这个变量很有用,例如easyswoole就需要通过该变量获取到,输入的参数。 需要注意的是,好像$_SERVER['argv']也可以获取参数,thinkphp6里的Input类是用这个获取参数
2022年10月18日
279 阅读
0 评论
0 点赞
2022-10-18
PHP中使用Trait实现单例模式 | 深入理解PHP设计模式
<?php trait Singleton { private static $instance; /** * @param mixed ...$args * @return static */ static function getInstance(...$args) { if (!isset(static::$instance)) { static::$instance = new static(...$args); } return static::$instance; } } class Test { use Singleton; public function __construct($a, $b, $c) { echo $a, $b, $c; } } Test::getInstance(1, 2, 3); // 输出123
2022年10月18日
269 阅读
1 评论
0 点赞
2022-09-29
PHP的Hash Map教程:深度解析与应用
概述 php数组原理大概是这样的: 首先有个散列表,然后通过“times 33”hash算法计算key得到一个整形值,把key存在这个位置上;然后要找到这个位置的是,只需要计算key的整型值,与散列的总大小取模得到在散列表中的存储位置了。 由于key的散列表上,存有value的内存地址,所以很快就找到key对于的值了。 //Bucket:散列表中存储的元素 typedef struct _Bucket { zval val; //存储的具体value,这里嵌入了一个zval,而不是一个指针 zend_ulong h; //key根据times 33计算得到的哈希值,或者是数值索引编号 zend_string *key; //存储元素的key } Bucket; //HashTable结构 typedef struct _zend_array HashTable; struct _zend_array { zend_refcounted_h gc; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, zend_uchar reserve) } v; uint32_t flags; } u; uint32_t nTableMask; //哈希值计算掩码,等于nTableSize的负值(nTableMask = -nTableSize) Bucket *arData; //存储元素数组,指向第一个Bucket uint32_t nNumUsed; //已用Bucket数 uint32_t nNumOfElements; //哈希表有效元素数 uint32_t nTableSize; //哈希表总大小,为2的n次方 uint32_t nInternalPointer; zend_long nNextFreeElement; //下一个可用的数值索引,如:arr[] = 1;arr["a"] = 2;arr[] = 3; 则nNextFreeElement = 2; dtor_func_t pDestructor; }; arData HashTable中一个非常重要的值arData,存着数组值和数组的key的散列表: 插入数组value元素时按顺序 依次插入 数组,比如第一个元素在arData[0]、第二个在arData[1]...arData[nNumUsed],PHP数组的有序性正是通过arData保证的 key的散列表,是在第一个value元素之前,分配内存时这个散列表与Bucket数组一起分配,因为arData这个值指向存储元素数组的第一个Bucket,所以可以通过arData[-1]、arData[-2]、arData[-3]......来访问到key散列表的位置; 所以,整体来看HashTable主要依赖arData实现元素的存储、索引。插入一个元素时先将元素按先后顺序插入Bucket数组,位置是idx,再根据key的哈希值映射到散列表中的某个位置nIndex,将idx存入这个位置;查找时先在散列表中映射到nIndex,得到value在Bucket数组的位置idx,再从Bucket数组中取出元素。比如: $arr["a"] = 1; $arr["b"] = 2; $arr["c"] = 3; $arr["d"] = 4; unset($arr["c"]); 对应的HashTable如下图所示 nNumUsed、nNumOfElements nNumOfElements哈希表有效元素数,nNumUsed已用Bucket数。 当将一个元素从哈希表删除时并不会将对应的Bucket移除,而是将Bucket存储的zval修改为IS_UNDEF,也就是nNumOfElements数量减少,只有扩容时发现nNumOfElements与nNumUsed相差达到一定数量时才会将已删除的元素全部移除,重新构建哈希表,所以nNumUsed>=nNumOfElements。 哈希碰撞 哈希碰撞是指 不同的key 可能计算得到相同的哈希值(数值索引的哈希值直接就是数值本身),但是这些值又需要插入同一个散列表。一般解决方法是将Bucket串成链表,查找时遍历链表比较key。 最理想的链表是 从上往下,或者从下往上的结构,现在因为有hash冲突 那么整个链表应该是从上往下,或者从下往上 而相同hashcode又在同一行像又拓展,所以key的hash表变成了以下这种方式。 扩容 散列表可存储的value数是固定的,当空间不够用时就要进行扩容了。 PHP散列表的大小为2^n,插入时如果容量不够则首先检查已删除元素所占比例,如果达到阈值,则将已删除元素移除,重建索引,如果未到阈值则进行扩容操作,扩大为当前大小的2倍,将当前Bucket数组复制到新的空间,然后重建索引。 参考 https://github.com/pangudashu/php7-internal/blob/master/2/zend_ht.md
2022年09月29日
297 阅读
0 评论
0 点赞
2022-09-29
深入了解PHP的Zval - PHP内核的关键概念
概述 变量是一个语言实现的基础,变量有两个组成部分:变量名、变量值,PHP中可以将其对应为:zval、zend_value,这两个概念一定要区分开,PHP中变量的内存是通过引用计数进行管理的,而且PHP7中引用计数是在zend_value而不是zval上,变量之间的传递、赋值通常也是针对zend_value。 php7的变量的基础结构: // zend_value结构体,保存具体变量类型的值或指针 typedef union _zend_value { zend_long lval; //int整形 double dval; //浮点型 zend_refcounted *counted; zend_string *str; //string字符串 zend_array *arr; //array数组 zend_object *obj; //object对象 zend_resource *res; //resource资源类型 zend_reference *ref; //引用类型,通过&$var_name定义的 zend_ast_ref *ast; //下面几个都是内核使用的value zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww; } zend_value; //zend_types.h zval结构体 typedef struct _zval_struct zval; struct _zval_struct { zend_value value; //变量实际的value // u1 主要是用于保存变量的类型 union { struct { ZEND_ENDIAN_LOHI_4( //这个是为了兼容大小字节序,小字节序就是下面的顺序,大字节序则下面4个顺序翻转 zend_uchar type, //变量类型 zend_uchar type_flags, //类型掩码,不同的类型会有不同的几种属性,内存管理会用到 zend_uchar const_flags, zend_uchar reserved) //call info,zend执行流程会用到 } v; uint32_t type_info; //上面4个值的组合值,可以直接根据type_info取到4个对应位置的值 } u1; // 这个值纯粹是个辅助值 union { uint32_t var_flags; uint32_t next; //哈希表中解决哈希冲突时用到 uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ } u2; //一些辅助值 }; 重点:zval的结构体由,一个union类型的zend_value和两个union:u1、u2组成,他们的大小为16个字节。 zend_value根据类型存储各自的值或者指针,对于整型和浮点型这种简单的数值字节存储,否则存的是值的指针,占用8个字节; u1是用于存储变量的类型,变量的类型就通过u1.v.type区分,其它几个应该都是变量的类型,只是不同场景用不同的值。 u2是一个扩展的值。 zvalue结构体 这里举例几个了解下就好。 zvalue标量类型存储 最简单的类型是true、false、long、double、null,其中true、false、null没有value,直接根据type区分,而long、double的值则直接存在value中:zend_long、double,也就是标量类型不需要额外的value指针。 zvalue字符串类型存储 通过指针指向字符串结构体 struct _zend_string { zend_refcounted_h gc;// 变量引用信息,比如当前value的引用数,所有用到引用计数的变量类型都会有这个结构 zend_ulong h; // 哈希值,数组中计算索引时会用到 size_t len; //字符串长度,通过这个值保证二进制安全 char val[1];//字符串内容,变长struct,分配时按len长度申请内存 }; 引用类型 &首先会创建一个zend_reference结构,其内嵌了一个zval,这个zval的value指向原来zval的value(如果是布尔、整形、浮点则直接复制原来的值),然后将原zval的类型修改为IS_REFERENCE,原zval的value指向新创建的zend_reference结构。 struct _zend_reference { zend_refcounted_h gc;// 引用计数 zval val;// }; 例如: $a = "time:" . time(); //$a -> zend_string_1(refcount=1) $b = &$a; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=1) // 通过以下函数可以调试 xdebug_debug_zval('a'); xdebug_debug_zval('b'); 最终的结果如图: 注意:引用只能通过&产生,无法通过赋值传递,比如: $a = "time:" . time(); //$a -> zend_string_1(refcount=1) $b = &$a; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=1) $c = $b; //$a,$b -> zend_reference_1(refcount=2) -> zend_string_1(refcount=2) //$c -> $b = &$a这时候$a、$b的类型是引用,但是$c = $b并不会直接将$b赋值给$c,而是把$b实际指向的zval赋值给$c。 这个也表示PHP中的 引用只可能有一层 ,不会出现一个引用指向另外一个引用的情况 ,也就是没有C语言中指针的指针的概念 内存管理 因为如果对变量都是做拷贝的话,对于字符串、数组、对象等结构,对性能的开销很大,所以php里的方案是:引用计数+写时复制。 引用计数 引用计数是指在value中增加一个字段refcount记录指向当前value的数量,变量复制、函数传参时并不直接硬拷贝一份value数据,而是将refcount++,变量销毁时将refcount--,等到refcount减为0时表示已经没有变量引用这个value,将它销毁即可。 $a = "time:" . time(); //$a -> zend_string_1(refcount=1) $b = $a; //$a,$b -> zend_string_1(refcount=2) $c = $b; //$a,$b,$c -> zend_string_1(refcount=3) unset($b); //$b = IS_UNDEF $a,$c -> zend_string_1(refcount=2) 例外: $a = "hi~"; $b = $a; // $a,$b -> zend_string_1(refcount=0,val="hi~"),引用计数却是0 事实上并不是所有的PHP变量都会用到引用计数,标量:true/false/double/long/null是硬拷贝自然不需要这种机制,但是除了这几个还有两个特殊的类型也不会用到: interned string,内部字符串,我们在PHP中写的所有字符都可以认为是这种类型,比如function name、class name、variable name、静态字符串等等,我们这样定义:$a = "hi~";后面的字符串内容是唯一不变的,这些字符串等同于C语言中定义在静态变量区的字符串:char *a = "hi~";,这些字符串的生命周期为request期间,request完成后会统一销毁释放,自然也就无需在运行期间通过引用计数管理内存。 immutable array,只有在用opcache的时候才会用到这种类型,不清楚具体实现,暂时忽略。 写时复制 多个变量可能指向同一个value,然后通过refcount统计引用数,这时候如果其中一个变量试图更改value的内容则会重新拷贝一份value修改,同时断开旧的指向,写时复制的机制在计算机系统中有非常广的应用,它只有在必要的时候(写)才会发生硬拷贝,可以很好的提高效率,下面从示例看下: $a = array(1,2); $b = &$a; $c = $a; //发生分离 $b[] = 3; 最终的结果: 不是所有类型都可以copy的,比如对象、资源,事实上只有string、array两种支持,与引用计数相同,也是通过zval.u1.type_flag标识value是否可复制的,也就是说变量有个copyable的属性。 变量回收 PHP变量的回收主要有两种:主动销毁、自动销毁。 主动销毁指的就是 unset 而自动销毁就是PHP的自动管理机制,在return时减掉局部变量的refcount,即使没有显式的return,PHP也会自动给加上这个操作,另外一个就是写时复制时会断开原来value的指向,这时候也会检查断开后旧value的refcount。 垃圾回收 PHP变量的回收是根据refcount实现的,当unset、return时会将变量的引用计数减掉,如果refcount减到0则直接释放value,这是变量的简单gc过程,但是实际过程中出现gc无法回收导致内存泄漏的bug,先看下一个例子: $a = [1]; $a[] = &$a; unset($a); unset($a)之前引用关系: ![l8mdvidm.png](https://www.xiaoqiuyinboke.cn/usr/uploads/2022/09/107427356.png) unset($a)之后 可以看到,unset($a)之后由于数组中有子元素指向$a,所以refcount > 0,无法通过简单的gc机制回收,这种变量就是垃圾,垃圾回收器要处理的就是这种情况,目前垃圾只会出现在array、object两种类型中,所以只会针对这两种情况作特殊处理:当销毁一个变量时,如果发现减掉refcount后仍然大于0,且类型是IS_ARRAY、IS_OBJECT则将此value放入gc可能垃圾双向链表中,等这个链表达到一定数量后启动检查程序将所有变量检查一遍,如果确定是垃圾则销毁释放。 参考 https://github.com/pangudashu/php7-internal/blob/master/2/zval.md
2022年09月29日
302 阅读
0 评论
0 点赞
2022-09-28
PHP 的生命周期理解和应用
模块初始化阶段->请求初始化阶段->执行PHP脚本阶段->请求结束阶段->模块关闭阶段
2022年09月28日
263 阅读
0 评论
0 点赞
1
2
...
5