Record a memory leak caused by improper use of Larave Http Client Author: Chuwen Time: 2023-12-06 Classification: PHP comment ##Background Larave's [HTTP Client]( https://laravel.com/docs/10.x/http-client "HTTP Client") is based on the secondary encapsulation of Guzzle, which is very convenient for operation, so I wrote similar codes in the business code ```php $url = ' https://xxxx/xxx.json '; $json = Illuminate\Support\Facades\Http::get($url)->json(); //TODO business logic processing ``` The project uses [laravels]( https://github.com/hhxsv5/laravel-s "Laravels"), so the project is resident in memory, but it is observed that the worker memory will increase slowly with the number of requests, and will not automatically reclaim the memory, resulting in an abnormal termination of the program due to insufficient memory: ``` PHP Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 360448 bytes) in /Users/shine/work/xxxxxx-project/vendor/guzzlehttp/psr7/src/Utils.php on line 414 Symfony\Component\ErrorHandler\Error\FatalError Allowed memory size of 67108864 bytes exhausted (tried to allocate 360448 bytes) at vendor/guzzlehttp/psr7/src/Utils.php:414 410▕ }); 411▕ 412▕ try { 413▕ /** @var string|false $contents */ ➜ 414▕ $contents = stream_get_contents($stream); 415▕ 416▕ if ($contents === false) { 417▕ $ex = new \RuntimeException('Unable to read stream contents'); 418▕ } Whoops\Exception\ErrorException Allowed memory size of 67108864 bytes exhausted (tried to allocate 360448 bytes) at vendor/guzzlehttp/psr7/src/Utils.php:414 410▕ }); 411▕ 412▕ try { 413▕ /** @var string|false $contents */ ➜ 414▕ $contents = stream_get_contents($stream); 415▕ 416▕ if ($contents === false) { 417▕ $ex = new \RuntimeException('Unable to read stream contents'); 418▕ } +1 vendor frames 2 [internal]:0 Whoops\Run::handleShutdown() ``` ##Solution By studying the framework code, it is found that Guzzle stream is not closed normally, which causes the memory to accumulate and cannot be recycled Then, in [vendor/larravel/framework/src/Illuminate/Http/Client/Response. php: 247]( https://github.com/laravel/framework/blob/10.x/src/Illuminate/Http/Client/Response.php#L247 "Vendor/larravel/framework/src/Illuminate/Http/Client/Response. php: 247") found a method of 'close()', but this method is not used anywhere. It should be called manually to close stream So change the code as follows ```php $url = ' https://xxxx/xxx.json '; $response = Illuminate\Support\Facades\Http::get($url); $json = $response->json(); //Close stream $response->close(); //TODO business logic processing ``` ##Attached with test memory leak code ```php <? php $i = 0; while (true) { $url = ' http://127.0.0.1:7788/composer.lock '; $json = Illuminate\Support\Facades\Http::get($url)->json(); printf("Count: %d\tPHP Memory: %.1fMB\n", $i++, memory_get_usage(true) / 1024.00 / 1024.00); } ``` ! []( https://cdn.nowtime.cc/2023/12/06/138987942.png ) ##Attached is the code after the test fixes the memory leak ```php <? php $i = 0; while (true) { $url = ' http://127.0.0.1:7788/composer.lock '; $response = Illuminate\Support\Facades\Http::get($url); printf("Count: %d\tPHP Memory: %.1fMB\tResponse size: %.2fKB\n", $i++, memory_get_usage(true) / 1024.00 / 1024.00, strlen($response->body()) / 1024); $response->close(); } ``` ! []( https://cdn.nowtime.cc/2023/12/06/3782614807.png )
PHP 8.1 Enum (enumeration) Get enumeration by name Author: Chuwen Time: 2023-09-21 Classification: PHP comment Inspired by: https://github.com/php/php-src/issues/9352#issuecomment -1216839118 ```php <? php enum Gender { case UNKNOWN; case MALE; case FEMALE; } /** * @template T as BackedEnum|UnitEnum * @param class-string<T> $enumClass * @param string $name * @return T|null */ function tryFromName(string $enumClass, string $name) { $constName = $enumClass . '::' . $ name; return is_subclass_of($enumClass, UnitEnum::class) && defined($constName) ? constant($constName) : null; } // enum(Gender::UNKNOWN) var_dump(tryFromName(Gender::class, 'UNKNOWN')); // enum(Gender::MALE) var_dump(tryFromName(Gender::class, 'MALE')); // enum(Gender::FEMALE) var_dump(tryFromName(Gender::class, 'FEMALE')); // NULL var_dump(tryFromName(Gender::class, 'null')); ```
Php cs fix only formats the modified code/only formats the submitted code Author: Chuwen Time: 2023-09-21 Classification: PHP comment ##Premises Note that you need to add 'cs fix': "php cs fix $1" 'in the' scripts: 'section of' composer. json ', as shown in the following example ```json { "name": "hyperf/hyperf-skeleton", "type": "project", // ... "autoload": { "psr-4": { "App\\": "app/" }, "files": [] }, "scripts": { // ...... "cs-fix": "php-cs-fixer fix $1", // ...... }, } ``` ##Command ###Only format the modified code ```shell git diff --name-only --cached | grep '\.php$' | xargs -n1 composer cs-fix ``` 1. 'git diff -- name only -- cached': This part of the command is used to obtain the list of modified files that you have staged. 2. 'grep' . Php $'': pipe the file list to the grep command, which will only select files with the extension '. php'. 3. 'xargs - n1 composer cs fix': The xargs command passes each file name as a parameter to the 'composer cs fix' command to format the code of each file. ###Format a submitted code ```shell git diff-tree --no-commit-id --name-only -r <commit-hash> | grep '\.php$' | xargs -n1 composer cs-fix ``` 1. 'git diff tree -- no commit id -- name only - r<commit hash>': This command obtains the modified file list in a specific submission record. >* *<commit hash>* * Can be obtained from ` git log ' 2. 'grep' . Php $'': pipe the file list to the 'grep' command, which will select only files with the extension '. php'. 3. The 'xargs - n1 composer cs fix': 'xargs' command passes each file name as a parameter to the' composer cs fix 'command to format the code of each file.
Pecl install spool installation error: fatal error: pcre2. h: No such file or directory Author: Chuwen Time: 2023-09-19 Classification: PHP , Other classifications comment Installation error log: ```log In file included from /home/linuxbrew/.linuxbrew/Cellar/ php@8.1 /8.1.23/include/php/ext/spl/spl_iterators.h:22, from /home/linuxbrew/.linuxbrew/Cellar/ php@8.1 /8.1.23/include/php/ext/spl/spl_array.h:22, from /tmp/pear/temp/swoole/ext-src/swoole_coroutine.cc:27: /home/linuxbrew/.linuxbrew/Cellar/ php@8.1 /8.1.23/include/php/ext/pcre/php_pcre.h:23:10: fatal error: pcre2.h: No such file or directory 23 | #include "pcre2.h" | ^~~~~~~~~ compilation terminated. make: *** [Makefile:233: ext-src/swoole_coroutine.lo] Error 1 ERROR: `make' failed ``` ##Error reason This error message indicates that the pcre2. h header file is missing in the compilation or construction process, so it cannot be found. Pcre2. h is the header file of PCRE2 (Perl Compatible Regular Expressions) library, which is usually used for regular expression operations. ##Solution **Installing the PCRE2 Library** On Ubuntu/Debian: ```shell sudo apt-get install libpcre2-dev ``` On CentOS/RHEL: ```shell sudo yum install pcre2-devel ``` On the macOS, you can use Homebrew to install: ```shell brew install pcre2 ``` Finally, the solution is perfect. I normally install the 'swoole' extension here ``` Build process completed successfully Installing '/home/linuxbrew/.linuxbrew/Cellar/ php@8.1 /8.1.23/pecl/20210902/swoole.so' Installing '/home/linuxbrew/.linuxbrew/Cellar/ php@8.1 /8.1.23/include/php/ext/swoole/config.h' Installing '/home/linuxbrew/.linuxbrew/Cellar/ php@8.1 /8.1.23/include/php/ext/swoole/php_swoole.h' install ok: channel://pecl.php.net/swoole-5.0.3 Extension swoole enabled in php.ini ```
Brew Install any version of PHP (7.3, 7.4, 8.0, 8.1, 8.2, 8.3) Author: Chuwen Time: 2023-09-19 Classification: Linux comment ##Dependencies * [brew]( https://brew.sh/ "brew") ##Installation First add the 'shivammathur/php' warehouse source: ```shell brew tap shivammathur/php ``` Search for installable PHP versions ` brew search shivammathur/php` ```shell shine@shine :~/work/xxxxx-web$ brew search shivammathur/php ==> Formulae shivammathur/php/php shivammathur/php/ php@7.0-debug shivammathur/php/ php@7.3 shivammathur/php/ php@8.0-debug shivammathur/php/ php@8.4 shivammathur/php/php-debug shivammathur/php/ php@7.1 shivammathur/php/ php@7.3-debug shivammathur/php/ php@8.1 shivammathur/php/ php@8.4-debug shivammathur/php/ php@5.6 shivammathur/php/ php@7.1-debug shivammathur/php/ php@7.4 shivammathur/php/ php@8.1-debug shivammathur/php/ php@5.6-debug shivammathur/php/ php@7.2 shivammathur/php/ php@7.4-debug shivammathur/php/ php@8.3 shivammathur/php/ php@7.0 shivammathur/php/ php@7.2-debug shivammathur/php/ php@8.0 shivammathur/php/ php@8.3-debug ``` For example, if you want these PHP versions, do as follows: * PHP 8.1:`brew install shivammathur/php/ php@8.1 ` * PHP 8.2:`brew install shivammathur/php/ php@8.2 ` * PHP 8.3:`brew install shivammathur/php/ php@8.3 `