PHP7.4 새로운 확장 방법 FFI 자세한 설명
PHP7.4에는 매우 유용하다고 생각되는 확장 기능이 제공됩니다: PHP FFI(외부 함수 인터페이스)
, PHP FFI RFC의 설명 인용: PHP FFI(Foreign Function interface)
,引用一段PHP FFI RFC中的一段描述:
For PHP, FFI opens a way to write PHP extensions and bindings to C libraries in pure PHP.
是的,FFI提供了高级语言直接的互相调用,而对于PHP而言,FFI让我们可以方便的调用C语言写的各种库。
其实现有大量的PHP扩展是对一些已有的C库的包装,某些常用的mysqli
,curl,gettext
等,PECL中也有大量的类似扩展。
传统的方式,当我们需要用一些已有的C语言的库的能力的时候,我们需要用C语言写包装器,把他们包装成扩展,这个过程中就需要大家去学习PHP的扩展怎么写,当然现在也有一些方便的方式,某种Zephir
。但总还是有一些学习成本的,而有了FFI之后,我们就可以直接在PHP脚本中调用C语言写的库中的函数了。
而C语言几十年的历史中,积累积累的优秀的库,FFI直接让我们可以方便的享受这个庞大的资源了。
言归正传,今天我用一个例子来介绍,我们如何使用PHP来调用libcurl,来抓取一个网页的内容,为什么要用libcurl呢?PHP不是已经有了curl扩展了么?嗯,首先因为libcurl的api我比较熟,其次呢,正是因为有了,才好对比,传统扩展方式AS和FFI方式直接的易用性不是?
首先,某些我们就拿当前你看的这篇文章为例,我现在需要写一段代码来抓取它的内容,如果用传统的PHP的curl扩展,我们大概会这么写:
<?php $url = "https://www.laruence.com/2020/03/11/5475.html"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_exec($ch); curl_close($ch);
(因为我的网站是https的,所以会多一个设置SSL_VERIFYPEER
的操作)那如果是用FFI呢?
首先要启用PHP7.4的ext / ffi,需要注意的是PHP-FFI要求libffi-3以上。
然后,我们需要告诉PHP FFI我们要调用的函数原型是咋样的,这个我们可以使用FFI :: cdef
,它的原型是:
FFI::cdef([string $cdef = "" [, string $lib = null]]): FFI
在字符串$cdef
中,我们可以写C语言函数式申明,FFI会parse
它,了解到我们要在字符串$lib
这个库中调用的函数的签名是啥样的,在这个例子中,我们用到三一个libcurl的函数,它们的申明我们都可以在libcurl的文档里找到,某些关于curl_easy_init
。
具体到这个例子,我们写一个curl.php
,包含所有要申明的东西,代码如下:
$libcurl = FFI::cdef(<<<CTYPE void *curl_easy_init(); int curl_easy_setopt(void *curl, int option, ...); int curl_easy_perform(void *curl); void curl_easy_cleanup(void *handle); CTYPE , "libcurl.so" );
这里有个地方是,文档中写的是返回值是CURL *
,但事实上因为我们的示例中不会解引用它,只是传递,那就避免麻烦就用void *
代替。
然而还有个麻烦的事情是,PHP预定义好了:
로그인 후 복사
好了,定义部分就算完成了,现在我们完成实际逻辑部分,整个下来的代码会是:
<?php require "curl.php"; $url = "https://www.laruence.com/2020/03/11/5475.html"; $ch = $libcurl->curl_easy_init(); $libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch);
怎么样,比例使用curl扩展的方式,是不是一样简练呢?
接下来,我们稍微弄的复杂一点,也直到,如果我们不想要结果直接输出,而是返回成一个字符串呢,对于PHP的curl扩展来说,我们只需要调用curl_setop
把CURLOPT_RETURNTRANSFER
为1,但在libcurl中其实并没有直接返回字符串的能力,或者提供了一个WRITEFUNCTION
的替代函数,在有数据返回的时候,libcurl会调用这个函数,实际上PHP curl扩展也是这样做的。
目前我们并不能直接把一个PHP函数作为附加函数通过FFI传递给libcurl,那我们都有俩种方式来做:
1.采用WRITEDATA
,默认的libcurl会调用fwrite
作为一个变量函数,而我们可以通过WRITEDATA
给libcurl一个fd,让它不要写入stdout
,而是写入到这个fd
2.我们自己编写一个C到简单函数,通过FFI日期进来,传递给libcurl。
我们先用第一种方式,首先我们需要使用fopen
,这次我们通过定义一个C的头文件来申明原型(file.h
):
void *fopen(char *filename, char *mode); void fclose(void * fp);
像file.h
一样,我们把所有的libcurl的函数申明也放到curl.h
中去
#define FFI_LIB "libcurl.so" void *curl_easy_init(); int curl_easy_setopt(void *curl, int option, ...); int curl_easy_perform(void *curl); void curl_easy_cleanup(CURL *handle);
然后我们就可以使用FFI :: load
来加载.h文件:
static function load(string $filename): FFI;
但是怎么告诉FFI加载那个对应的库呢?如上面,我们通过定义了一个FFI_LIB
的宏,来告诉FFI这些函数来自libcurl.so
,当我们用FFI :: load
加载这个h文件的时候,PHP FFI就会自动加载libcurl.so
那为什么fopen
不需要指定加载库呢,那是因为FFI也会在变量符号表中查找符号,而fopen
PHP의 경우 FFI는 순수 PHP에서 PHP 확장 및 C 라이브러리에 대한 바인딩을 작성하는 방법입니다.예, FFI는 서로 직접 호출할 수 있는 고급 언어를 제공하며, PHP의 경우 FFI를 사용하면 다음으로 작성된 다양한 라이브러리를 편리하게 호출할 수 있습니다. C 언어. 🎜🎜실제로 일부 기존 C 라이브러리, 일반적으로 사용되는
mysqli
, 컬, gettext
등의 패키지인 PHP 확장이 많이 있습니다. PECL 유사한 확장에 그 중 다수가 있습니다. 🎜🎜기존 C 언어 라이브러리의 기능을 사용해야 하는 전통적인 방식에서는 C 언어로 래퍼를 작성하고 이를 확장으로 패키징해야 합니다. 이 과정에서 모든 사람은 물론 PHP 쓰기를 확장하는 방법을 배워야 합니다. , 이제 Zephir
와 같은 몇 가지 편리한 방법이 있습니다. 그러나 여전히 약간의 학습 비용이 있으며 FFI를 사용하면 PHP 스크립트에서 C 언어로 작성된 라이브러리의 함수를 직접 호출할 수 있습니다. 🎜🎜C 언어의 수십 년 역사 동안 우수한 라이브러리가 축적되었으며 FFI를 통해 이 거대한 리소스를 편리하게 즐길 수 있습니다. 🎜🎜다시 본론으로 돌아가서, 오늘은 PHP를 사용하여 libcurl을 호출하여 웹 페이지 콘텐츠를 크롤링하는 방법을 소개하는 예를 사용하겠습니다. 왜 libcurl을 사용합니까? PHP에는 이미 컬 확장 기능이 없나요? 글쎄요, 우선 저는 libcurl의 API에 익숙합니다. 둘째, 바로 그것 때문에 전통적인 확장 방식인 AS와 FFI 방식이 직접적으로 사용하기 더 쉽지 않습니까? 🎜🎜먼저 지금 읽고 있는 기사를 예로 들어보겠습니다. 이제 기사의 내용을 캡처하기 위한 코드를 작성해야 합니다. 기존 PHP 컬 확장을 사용하면 다음과 같이 작성할 것입니다. 🎜 (내 웹사이트가 https이기 때문에 SSL_VERIFYPEER
를 설정하는 작업이 한 번 더 필요합니다.) FFI를 사용하면 어떻게 되나요? 🎜🎜먼저 PHP7.4의 ext/ffi를 활성화하세요. PHP-FFI에는 libffi-3 이상이 필요하다는 점에 유의하세요. 🎜🎜그런 다음 호출하려는 함수의 프로토타입이 무엇인지 PHP FFI에 알려야 합니다. 이를 위해 FFI::cdef
를 사용할 수 있으며 해당 프로토타입은 다음과 같습니다. 🎜<?php const CURLOPT_URL = 10002; const CURLOPT_SSL_VERIFYPEER = 64; const CURLOPT_WRITEDATA = 10001; $libc = FFI::load("file.h"); $libcurl = FFI::load("curl.h"); $url = "https://www.laruence.com/2020/03/11/5475.html"; $tmpfile = "/tmp/tmpfile.out"; $ch = $libcurl->curl_easy_init(); $fp = $libc->fopen($tmpfile, "a"); $libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEDATA, $fp); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch); $libc->fclose($fp); $ret = file_get_contents($tmpfile); @unlink($tmpfile);
$cdef
에서 C 언어 함수 선언을 작성할 수 있으며, FFI는 이를 파싱
하고 $lib</ 문자열에서 호출하려고 한다는 것을 이해합니다. code> 라이브러리 함수의 서명은 무엇입니까? 이 예에서는 세 가지 libcurl 함수를 사용합니다. 해당 선언은 libcurl 문서에서 찾을 수 있으며 일부는 <code>curl_easy_init
에 관한 것입니다. 🎜🎜특히 이 예에서는 선언할 모든 내용이 포함된 curl.php
를 작성합니다. 코드는 다음과 같습니다. 🎜#include <stdlib.h> #include <string.h> #include "write.h" size_t own_writefunc(void *ptr, size_t size, size_t nmember, void *data) { own_write_data *d = (own_write_data*)data; size_t total = size * nmember; if (d->buf == NULL) { d->buf = malloc(total); if (d->buf == NULL) { return 0; } d->size = total; memcpy(d->buf, ptr, total); } else { d->buf = realloc(d->buf, d->size + total); if (d->buf == NULL) { return 0; } memcpy(d->buf + d->size, ptr, total); d->size += total; } return total; } void * init() { return &own_writefunc; }
CURL *
이지만 실제로 이 예에서는 역참조되지 않으므로 그냥 전달된 다음 문제를 방지하려면 대신 void *
를 사용하세요. 🎜🎜그러나 또 다른 귀찮은 점은 PHP가 다음을 미리 정의했다는 것입니다. 🎜#define FFI_LIB "write.so" typedef struct _writedata { void *buf; size_t size; } own_write_data; void *init();
gcc -O2 -fPIC -shared -g write.c -o write.so
curl_setop</ 코드만 호출하면 됩니다. ><code>CURLOPT_RETURNTRANSFER
를 1로 설정하지만 libcurl은 실제로 문자열을 직접 반환하는 기능이 없거나 데이터가 반환될 때 WRITEFUNCTION
에 대한 대체 함수를 제공합니다. libcurl이 호출합니다. 이 함수는 실제로 PHP 컬 확장도 동일한 기능을 수행합니다. 🎜🎜현재 FFI를 통해 libcurl에 추가 함수로 PHP 함수를 직접 전달할 수 없으므로 두 가지 방법이 있습니다. 🎜🎜1 WRITEDATA
를 사용하면 기본 libcurl이 < 코드를 호출합니다. >fwrite는 변수 함수이며 WRITEDATA
를 통해 libcurl에 fd를 제공하여 stdout
에 쓰지 않고 이 fd에 쓰도록 할 수 있습니다 🎜🎜 2. 간단한 함수에 C를 직접 작성하고 FFI 날짜를 전달한 후 libcurl에 전달합니다. 🎜🎜먼저 첫 번째 방법을 사용해 보겠습니다. 먼저 fopen
을 사용해야 합니다. 이번에는 C 헤더 파일(file.h
)을 정의하여 프로토타입을 선언합니다. 🎜 <?php const CURLOPT_URL = 10002; const CURLOPT_SSL_VERIFYPEER = 64; const CURLOPT_WRITEDATA = 10001; const CURLOPT_WRITEFUNCTION = 20011; $libcurl = FFI::load("curl.h"); $write = FFI::load("write.h"); $url = "https://www.laruence.com/2020/03/11/5475.html"; $data = $write->new("own_write_data"); $ch = $libcurl->curl_easy_init(); $libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEDATA, FFI::addr($data)); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEFUNCTION, $write->init()); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch); ret = FFI::string($data->buf, $data->size);
file.h
처럼 모든 libcurl 함수 선언을 curl.h
에 넣습니다.🎜
function FFI::new(mixed $type [, bool $own = true [, bool $persistent = false]]): FFI\CData
FFI::load</를 사용할 수 있습니다. code>를 사용하여 .h 파일을 로드합니다. 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>static function addr(FFI\CData $cdata): FFI\CData;</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>🎜하지만 FFI에게 해당 라이브러리를 로드하도록 지시하는 방법은 무엇입니까? 위와 같이 <code>FFI_LIB
매크로를 정의하여 이러한 함수가 libcurl.so
에서 온 것임을 FFI에 알립니다. 이 h 파일을 사용하면 PHP FFI가 자동으로 libcurl.so를 로드합니다.so🎜🎜그렇다면 fopen
이 로딩 라이브러리를 지정할 필요가 없는 이유는 FFI가 변수 기호 테이블에서도 기호를 찾기 때문입니다. code>fopen은 오랫동안 존재해 온 표준 라이브러리 함수입니다. 🎜🎜좋아, 이제 전체 코드는 다음과 같습니다: 🎜<?php const CURLOPT_URL = 10002; const CURLOPT_SSL_VERIFYPEER = 64; const CURLOPT_WRITEDATA = 10001; $libc = FFI::load("file.h"); $libcurl = FFI::load("curl.h"); $url = "https://www.laruence.com/2020/03/11/5475.html"; $tmpfile = "/tmp/tmpfile.out"; $ch = $libcurl->curl_easy_init(); $fp = $libc->fopen($tmpfile, "a"); $libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEDATA, $fp); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch); $libc->fclose($fp); $ret = file_get_contents($tmpfile); @unlink($tmpfile);
但这种方式呢就是需要一个临时的中转文件,还是不够优雅,现在我们用第二种方式,要用第二种方式,我们需要自己用C写一个替代函数传递给libcurl:
#include <stdlib.h> #include <string.h> #include "write.h" size_t own_writefunc(void *ptr, size_t size, size_t nmember, void *data) { own_write_data *d = (own_write_data*)data; size_t total = size * nmember; if (d->buf == NULL) { d->buf = malloc(total); if (d->buf == NULL) { return 0; } d->size = total; memcpy(d->buf, ptr, total); } else { d->buf = realloc(d->buf, d->size + total); if (d->buf == NULL) { return 0; } memcpy(d->buf + d->size, ptr, total); d->size += total; } return total; } void * init() { return &own_writefunc; }
注意此处的初始函数,因为在PHP FFI中,就目前的版本(2020-03-11)我们没有办法直接获得一个函数指针,所以我们定义了这个函数,返回own_writefunc
的地址。
最后我们定义上面用到的头文件write.h
:
#define FFI_LIB "write.so" typedef struct _writedata { void *buf; size_t size; } own_write_data; void *init();
注意到我们在头文件中也定义了FFI_LIB
,这样这个头文件就可以同时被write.c
和接下来我们的PHP FFI
共同使用了。
然后我们编译write
函数为一个动态库:
gcc -O2 -fPIC -shared -g write.c -o write.so
好了,现在整个的代码会变成:
<?php const CURLOPT_URL = 10002; const CURLOPT_SSL_VERIFYPEER = 64; const CURLOPT_WRITEDATA = 10001; const CURLOPT_WRITEFUNCTION = 20011; $libcurl = FFI::load("curl.h"); $write = FFI::load("write.h"); $url = "https://www.laruence.com/2020/03/11/5475.html"; $data = $write->new("own_write_data"); $ch = $libcurl->curl_easy_init(); $libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEDATA, FFI::addr($data)); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEFUNCTION, $write->init()); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch); ret = FFI::string($data->buf, $data->size);
此处,我们使用FFI :: new($ write-> new)
来分配了一个结构_write_data
的内存:
function FFI::new(mixed $type [, bool $own = true [, bool $persistent = false]]): FFI\CData
$own
表示这个内存管理是否采用PHP的内存管理,有时的情况下,我们申请的内存会经过PHP的生命周期管理,不需要主动释放,但是有的时候你也可能希望自己管理,那么可以设置$own
为flase
,那么在适当的时候,你需要调用FFI :: free
去主动释放。
然后我们把$data
作为WRITEDATA
传递给libcurl,这里我们使用了FFI :: addr
来获取$data
的实际内存地址:
static function addr(FFI\CData $cdata): FFI\CData;
然后我们把own_write_func
作为WRITEFUNCTION
传递给了libcurl,这样再有返回的时候,libcurl就会调用我们的own_write_func
来处理返回,同时会把write_data
作为自定义参数传递给我们的替代函数。
最后我们使用了FFI :: string
来把一段内存转换成PHP的string
:
static function FFI::string(FFI\CData $src [, int $size]): string
好了,跑一下吧?
然而毕竟直接在PHP中每次请求都加载so的话,会是一个很大的性能问题,所以我们也可以采用preload
的方式,这种模式下,我们通过opcache.preload
来在PHP启动的时候就加载好:
ffi.enable=1 opcache.preload=ffi_preload.inc
ffi_preload.inc:
<?php FFI::load("curl.h"); FFI::load("write.h");
但我们引用加载的FFI呢?因此我们需要修改一下这俩个.h头文件,加入FFI_SCOPE
,比如curl.h
:
#define FFI_LIB "libcurl.so" #define FFI_SCOPE "libcurl" void *curl_easy_init(); int curl_easy_setopt(void *curl, int option, ...); int curl_easy_perform(void *curl); void curl_easy_cleanup(void *handle);
对应的我们给write.h
也加入FFI_SCOPE
为“ write”,然后我们的脚本现在看起来应该是这样的:
<?php const CURLOPT_URL = 10002; const CURLOPT_SSL_VERIFYPEER = 64; const CURLOPT_WRITEDATA = 10001; const CURLOPT_WRITEFUNCTION = 20011; $libcurl = FFI::scope("libcurl"); $write = FFI::scope("write"); $url = "https://www.laruence.com/2020/03/11/5475.html"; $data = $write->new("own_write_data"); $ch = $libcurl->curl_easy_init(); $libcurl->curl_easy_setopt($ch, CURLOPT_URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEDATA, FFI::addr($data)); $libcurl->curl_easy_setopt($ch, CURLOPT_WRITEFUNCTION, $write->init()); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch); ret = FFI::string($data->buf, $data->size);
也就是,我们现在使用FFI :: scope
来代替FFI :: load
,引用对应的函数。
static function scope(string $name): FFI;
然后还有另外一个问题,FFI虽然给了我们很大的规模,但是毕竟直接调用C库函数,还是非常具有风险性的,我们应该只允许用户调用我们确认过的函数,于是,ffi.enable = preload
就该上场了,当我们设置ffi.enable = preload
的话,那就只有在opcache.preload
的脚本中的函数才能调用FFI,而用户写的函数是没有办法直接调用的。
我们稍微修改下ffi_preload.inc
变成ffi_safe_preload.inc
<?php class CURLOPT { const URL = 10002; const SSL_VERIFYHOST = 81; const SSL_VERIFYPEER = 64; const WRITEDATA = 10001; const WRITEFUNCTION = 20011; } FFI::load("curl.h"); FFI::load("write.h"); function get_libcurl() : FFI { return FFI::scope("libcurl"); } function get_write_data($write) : FFI\CData { return $write->new("own_write_data"); } function get_write() : FFI { return FFI::scope("write"); } function get_data_addr($data) : FFI\CData { return FFI::addr($data); } function paser_libcurl_ret($data) :string{ return FFI::string($data->buf, $data->size); }
也就是,我们把所有会调用FFI API的函数都定义在preload
脚本中,然后我们的示例会变成(ffi_safe.php
):
<?php $libcurl = get_libcurl(); $write = get_write(); $data = get_write_data($write); $url = "https://www.laruence.com/2020/03/11/5475.html"; $ch = $libcurl->curl_easy_init(); $libcurl->curl_easy_setopt($ch, CURLOPT::URL, $url); $libcurl->curl_easy_setopt($ch, CURLOPT::SSL_VERIFYPEER, 0); $libcurl->curl_easy_setopt($ch, CURLOPT::WRITEDATA, get_data_addr($data)); $libcurl->curl_easy_setopt($ch, CURLOPT::WRITEFUNCTION, $write->init()); $libcurl->curl_easy_perform($ch); $libcurl->curl_easy_cleanup($ch); $ret = paser_libcurl_ret($data);
这样一来通过ffi.enable = preload
,我们就可以限制,所有的FFI API只能被我们可控制的preload
脚本调用,用户不能直接调用。从而我们可以在这些函数内部做好适当的安全保证工作,从而保证一定的安全性。
好了,经历了这个例子,大家应该对FFI有一个比较深入的理解了,详细的PHP API说明,大家可以参考:PHP-FFI Manual,有兴趣的话,就去找一个C库,试试吧?
本文的例子,你可以在我的github上下载到:FFI example
最后还是多说一句,例子只是为了演示功能,所以省掉了很多错误分支的判断捕获,大家自己写的时候还是要加入。毕竟使用FFI的话,会让你会有1000种方式让PHP segfault crash,所以be careful
推荐PHP教程《PHP7》
위 내용은 PHP7.4 새로운 확장 방법 FFI 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

VS Code라고도 알려진 Visual Studio Code는 모든 주요 운영 체제에서 사용할 수 있는 무료 소스 코드 편집기 또는 통합 개발 환경(IDE)입니다. 다양한 프로그래밍 언어에 대한 대규모 확장 모음을 통해 VS Code는

숙련된 PHP 개발자라면 이미 그런 일을 해왔다는 느낌을 받을 것입니다. 귀하는 상당한 수의 애플리케이션을 개발하고, 수백만 줄의 코드를 디버깅하고, 여러 스크립트를 수정하여 작업을 수행했습니다.

이 튜토리얼은 PHP를 사용하여 XML 문서를 효율적으로 처리하는 방법을 보여줍니다. XML (Extensible Markup Language)은 인간의 가독성과 기계 구문 분석을 위해 설계된 다목적 텍스트 기반 마크 업 언어입니다. 일반적으로 데이터 저장 AN에 사용됩니다

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

문자열은 문자, 숫자 및 기호를 포함하여 일련의 문자입니다. 이 튜토리얼은 다른 방법을 사용하여 PHP의 주어진 문자열의 모음 수를 계산하는 방법을 배웁니다. 영어의 모음은 A, E, I, O, U이며 대문자 또는 소문자 일 수 있습니다. 모음이란 무엇입니까? 모음은 특정 발음을 나타내는 알파벳 문자입니다. 대문자와 소문자를 포함하여 영어에는 5 개의 모음이 있습니다. a, e, i, o, u 예 1 입력 : String = "Tutorialspoint" 출력 : 6 설명하다 문자열의 "Tutorialspoint"의 모음은 u, o, i, a, o, i입니다. 총 6 개의 위안이 있습니다

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

PHP의 마법 방법은 무엇입니까? PHP의 마법 방법은 다음과 같습니다. 1. \ _ \ _ Construct, 객체를 초기화하는 데 사용됩니다. 2. \ _ \ _ 파괴, 자원을 정리하는 데 사용됩니다. 3. \ _ \ _ 호출, 존재하지 않는 메소드 호출을 처리하십시오. 4. \ _ \ _ get, 동적 속성 액세스를 구현하십시오. 5. \ _ \ _ Set, 동적 속성 설정을 구현하십시오. 이러한 방법은 특정 상황에서 자동으로 호출되어 코드 유연성과 효율성을 향상시킵니다.
