C ++でのPHP 7の拡張機能の作成

PHPコードでC ++ライブラリの機能を使用するには、拡張機能を作成する必要がありました。 それでも、第5バージョンから第7バージョンに1つの重い拡張機能が移植されました。



PHPの拡張機能の記述に関するドキュメントをGoogleで検索すると、基本的には、バージョン5に関連する2014年までのテキストになります。php.netWebサイト自体は断片的で古い情報を提供します。 5番目のバージョン。 オフサイトで見つかった最大値は、すでに記述されている拡張機能の移行に乏しい人です。



その結果、拡張機能を作成するための多かれ少なかれ明確なマナはPHPソースコードだけでした。PHPソースコードは、拡張機能を作成および移行するときにガイドされました。



実際、PHP APIは大きく変更されているため、PHP拡張機能でのC ++クラスのラップなどの最も詳細な記事でさえ、PHP 7の拡張機能を作成する際には特に役立ちません。



この記事ではLinuxでの作業について説明しています。Kubuntuがあります。 Windowsの場合、他の設定ファイルを作成する必要があります。また、prodにWindowsをインストールせず、WindowsでPHPを展開しないため、これはありがたくありません。これは理解できませんでした。



必要なもの



php-dev、gcc、phpソースコード。 ソースからビルドするために必要なすべてをインストールするためのコンボは、簡単にグーグルにすることができます。



写真で顔を識別する



顔を決定するために、OpenCVライブラリを使用します。バージョンでテストされました> = 2.3.1



拡張機能を作成するための出発点は、 ext_skel



ユーティリティです。 これにより、新しい拡張用の空白を作成できます。 このコマンドを実行した後に出てきたコードを編集します。



PHPソースコードの/ext



フォルダーに移動して実行する必要があります

新しい拡張子の名前を持つext_skel







 ./ext_skel --extname=phpcv
      
      





その後、新しく作成されたphpcvフォルダーをより便利な場所に移動できます。 tests



フォルダーとphpcv.c



config.m4



php_phpcv.h



phpcv.c



ファイルが必要です。 phpcv.c



ファイルのphpcv.c



すぐにphpcv.cpp



ます。



config.m4



これは、拡張機能をコンパイルするためにphpize



ユーティリティが使用する構成ファイルです。



このファイルは、特別なマクロを使用した一種のbashスクリプトです。 これらのマクロは、phpソースコードのacinclude.m4



およびaclocal.m4



で定義され、角かっこと句読点の言語で記述されています。 実際、「dnl」行で始まるコメントを読むだけで十分であり、これらのマクロが何をするかは多かれ少なかれ明確になります。



余分な部分は削除し、必要に応じてコードを修正します。



config.m4
 PHP_ARG_ENABLE(phpcv, whether to enable phpcv support, [ --enable-phpcv Enable phpcv support]) if test "$PHP_PHPCV" != "no"; then PHP_REQUIRE_CXX() SEARCH_PATH="/usr/local /usr /opt/local" SEARCH_FOR="/include/opencv2/opencv.hpp" if test -r $PHP_PHPCV/$SEARCH_FOR; then CV_DIR=$PHP_PHPCV else AC_MSG_CHECKING([for opencv in default path]) for i in $SEARCH_PATH ; do if test -r $i/$SEARCH_FOR; then CV_DIR=$i AC_MSG_RESULT(found in $i) break fi done fi if test -z "$CV_DIR"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([Please reinstall the OpenCV distribution]) fi AC_CHECK_HEADER([$CV_DIR/include/opencv2/objdetect/objdetect.hpp], [], AC_MSG_ERROR('opencv2/objdetect/objdetect.hpp' header not found)) AC_CHECK_HEADER([$CV_DIR/include/opencv2/highgui/highgui.hpp], [], AC_MSG_ERROR('opencv2/highgui/highgui.hpp' header not found)) PHP_ADD_LIBRARY_WITH_PATH(opencv_objdetect, $CV_DIR/lib, PHPCV_SHARED_LIBADD) PHP_ADD_LIBRARY_WITH_PATH(opencv_highgui, $CV_DIR/lib, PHPCV_SHARED_LIBADD) PHP_ADD_LIBRARY_WITH_PATH(opencv_imgproc, $CV_DIR/lib, PHPCV_SHARED_LIBADD) PHP_SUBST(PHPCV_SHARED_LIBADD) PHP_NEW_EXTENSION(phpcv, phpcv.cpp, $ext_shared,, -std=c++0x -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi
      
      







PHP_ARG_ENABLE -PHPをソースコードからビルドするプロセス中に拡張機能をオンまたはオフにできるフラグを設定します。

PHP_REQUIRE_CXX() -C ++を使用する場合に必要

次に、opencvを見つけるためのbashコード。

AC_CHECK_HEADER-必要なヘッダーファイルの存在を確認する

PHP_ADD_LIBRARY_WITH_PATH-共有ライブラリーの接続

Php_subst

PHP_NEW_EXTENSION-拡張機能名はここに示されます。*アセンブリプロセスに関係する.cppファイルがリストされ、コンパイラフラグが示されます。



php_phpcv.h



php_phpcv.h
 #ifndef PHP_PHPCV_H #define PHP_PHPCV_H #define PHP_PHPCV_EXTNAME "phpcv" #define PHP_PHPCV_VERSION "0.2.0" #ifdef HAVE_CONFIG_H #include "config.h" #endif extern "C" { #include "php.h" #include "ext/standard/info.h" } #ifdef ZTS #include "TSRM.h" #endif extern zend_module_entry phpcv_module_entry; #define phpext_phpcv_ptr &phpcv_module_entry #if defined(ZTS) && defined(COMPILE_DL_PHPCV) ZEND_TSRMLS_CACHE_EXTERN(); #endif #endif /* PHP_PHPCV_H */
      
      







ここでは、設計に注意を払う価値があります



extern "C" { ... }





これは、C ++コードとCコードPHPとの互換性のために必要です。



phpcv.cpp



最後に、C ++コードがあります。

顔を見つけるには、 cv :: CascadeClassifier :: detectMultiScale()メソッドを使用します。



拡張機能は単一の機能を提供します。ここにそのプロトタイプがあります。



 /** * @see cv::CascadeClassifier::detectMultiScale() * @param string $imgPath * @param string $cascadePath * @param double $scaleFactor * @param int $minNeighbors * * @return array */ function cv_detect_multiscale($imgPath, $cascadePath, $scaleFactor, $minNeighbors) { }
      
      





phpcv.cpp
 #include "php_phpcv.h" #include <opencv2/objdetect/objdetect.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> PHP_MINFO_FUNCTION(phpcv) { php_info_print_table_start(); php_info_print_table_header(2, "phpcv support", "enabled"); php_info_print_table_end(); } PHP_FUNCTION(cv_detect_multiscale) { char *imgPath = NULL, *cascadePath = NULL; long imgPathLen, cascadePathLen, minNeighbors; double scaleFactor, minWidth, minHeight; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssdl", &imgPath, &imgPathLen, &cascadePath, &cascadePathLen, &scaleFactor, &minNeighbors) == FAILURE) { RETURN_FALSE; } // Read Image cv::Mat image; image = cv::imread(imgPath, CV_LOAD_IMAGE_GRAYSCALE); if (image.empty()) { RETURN_FALSE; } equalizeHist(image, image); //min size for detected object, discarding objects smaller than this minWidth = image.size().width / 10; minHeight = image.size().height / 10; // Load Face cascade (.xml file) cv::CascadeClassifier faceCascade; if (!faceCascade.load(cascadePath)) { RETURN_FALSE; } // Detect faces std::vector<cv::Rect> faces; faceCascade.detectMultiScale(image, faces, scaleFactor, minNeighbors, 0, cv::Size(minWidth, minHeight)); array_init(return_value); // Build array to return for ( int i = 0; i < faces.size(); i++ ) { // Now we have: faces[i].x faces[i].y faces[i].width faces[i].height zval face; array_init(&face); add_assoc_long(&face, "x", faces[i].x); add_assoc_long(&face, "y", faces[i].y); add_assoc_long(&face, "w", faces[i].width); add_assoc_long(&face, "h", faces[i].height); add_next_index_zval(return_value, &face); } } const zend_function_entry phpcv_functions[] = { PHP_FE(cv_detect_multiscale, NULL) PHP_FE_END }; zend_module_entry phpcv_module_entry = { STANDARD_MODULE_HEADER, PHP_PHPCV_EXTNAME, phpcv_functions, NULL, NULL, NULL, NULL, PHP_MINFO(phpcv), PHP_PHPCV_VERSION, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PHPCV #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE(); #endif ZEND_GET_MODULE(phpcv) #endif
      
      







PHP_MINFO_FUNCTION-拡張機能に関する情報をphpinfo()出力に追加します

PHP_FUNCTION(cv_detect_multiscale) -関数のコード。 zend_parse_parameters



を使用して入力パラメーターを受け取った後、C ++コードzend_parse_parameters



ます。 opencvライブラリを使用して、面を見つけ、見つかった面の座標で出力配列を形成します。

zend_function_entry-拡張機能によって提供される関数をリストします。

zend_module_entry-標準構造、拡張機能を記述する構造。 連続したいくつかのNULL



拡張機能とリクエストの初期化とシャットダウン中に実行されるメソッドの代わりに、これらのフェーズでは何もしません。



コードでは、2つの魔法のダースに気付くことができます。 ここでは、検出する必要のある写真の最小および最大の顔サイズのパラメーターを渡すことに煩わされないことにしました。



テスト



拡張テストは、何かを出力して出力をチェックするコードで構成されます。 * .Phptファイルとテストはtests



フォルダーに配置されます。



002.phpt
 --TEST-- Test face detection --SKIPIF-- <?php if (!extension_loaded("phpcv")) print "skip"; ?> --FILE-- <?php $cascade = '/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml'; $img = __DIR__ . '/img.jpg'; $faces = cv_detect_multiscale($img, $cascade, 1.1, 5); if (is_array($faces) && count($faces) > 0) { echo 'face detection works'; } ?> --EXPECT-- face detection works
      
      







組み立てとテスト



収集:



 phpize && ./configure && make
      
      





テストするには:



 make test
      
      





日時パターンジェネレーター



ここで、C ++クラスをラップするクラスが提供する拡張機能について考えます。

intl拡張クラスのセットに不足している機能を追加します。 これが必要な理由: https : //blog.ksimka.io/a-long-journey-to-formatting-a-date-without-a-year-internationally-with-php/#header 要するに、標準のint拡張機能は、1年なしの日付、つまり「2月10日」または「2月10日」を国際的に生成する機能を提供しません。 この拡張機能はこの問題を修正します。



システムにはICUライブラリがインストールされている必要があります。 Debianのようなシステムでは、libicu-devパッケージをインストールできます。



config.m4



config.m4
 PHP_ARG_ENABLE(intl-dtpg, whether to enable intl-dtpg support, [ --enable-intl-dtpg Enable intl-dtpg support]) if test "$PHP_INTL_DTPG" != "no"; then PHP_SETUP_ICU(INTL_DTPG_SHARED_LIBADD) PHP_SUBST(INTL_DTPG_SHARED_LIBADD) PHP_REQUIRE_CXX() PHP_NEW_EXTENSION(intl_dtpg, intl_dtpg.cpp, $ext_shared,,-std=c++0x $ICU_INCS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi
      
      







今回はすべてが非常に簡潔です。 ICUライブラリが必要であり、int拡張モジュールも存在する必要があるため、int拡張モジュールからPHP_SETUP_ICUマクロを借用しました。

PHP_NEW_EXTENSIONでは、 $ICU_INCS



はICU固有のフラグです。



intl_dtpg.h



intl_dtpg.h
 #ifndef INTL_DTPG_H #define INTL_DTPG_H #include <zend_modules.h> #include <zend_types.h> #include <unicode/dtptngen.h> extern "C" { #include "php.h" #include "ext/standard/info.h" } extern zend_module_entry intl_dtpg_module_entry; #define phpext_intl_dtpg_ptr &intl_dtpg_module_entry #define INTL_DTPG_VERSION "1.0.0" #ifdef ZTS #include "TSRM.h" #endif typedef struct { DateTimePatternGenerator *dtpg; UErrorCode status; zend_object zo; } IntlDateTimePatternGenerator_object; static inline IntlDateTimePatternGenerator_object *php_intl_datetimepatterngenerator_fetch_object(zend_object *obj) { return (IntlDateTimePatternGenerator_object *)((char*)(obj) - XtOffsetOf(IntlDateTimePatternGenerator_object, zo)); } #if defined(ZTS) && defined(COMPILE_DL_INTL_DTPG) ZEND_TSRMLS_CACHE_EXTERN() #endif #endif /* INTL_DTPG_H */
      
      







ここで、 IntlDateTimePatternGenerator_object



の構造を定義します。 ICUライブラリからのDateTimePatternGenerator



オブジェクトへのポインター、ステータスを保存する変数、およびPHPクラスであるzend_object



オブジェクトを保存します。 これは、C ++クラスのラッパーです。 PHP APIはzend_object



オブジェクトを操作し、構造体にラップして、常にzend_object



「近所」にあるものにアクセスします。



以下に、 zend_object



オブジェクトを持つIntlDateTimePatternGenerator_object



構造体を取得するためのinline



関数の定義をzend_object



ます。 zend_object



では、構造体のサイズからzend_object



のサイズを引いた数だけ、 zend_object



の先頭からメモリステップを戻します。 したがって、私たちは構造の一番最初に自分自身を見つけ、それへのポインタが私たちに戻ります。 このようなトリッキーな方法は、intl拡張ソースコードで見張られています。



intl_dtpg.cpp



拡張機能は、クラスに次の構造を提供します。



 class IntlDateTimePatternGenerator { /** * @param string $locale */ public function __construct(string $locale) {} /** * Return the best pattern matching the input skeleton. * It is guaranteed to have all of the fields in the skeleton. * * @param string $skeleton The skeleton is a pattern containing only the variable fields. * For example, "MMMdd" and "mmhh" are skeletons. * @return string The best pattern found from the given skeleton. */ public function findBestPattern(string $skeleton) {} }
      
      





intl_dtpg.cpp
 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "intl_dtpg.h" #include <unicode/ustdio.h> #include <unicode/smpdtfmt.h> zend_class_entry *IntlDateTimePatternGenerator_ce; zend_object_handlers IntlDateTimePatternGenerator_object_handlers; /* {{{ IntlDateTimePatternGenerator_objects_dtor */ static void IntlDateTimePatternGenerator_object_dtor(zend_object *object) { zend_objects_destroy_object(object); } /* }}} */ /* {{{ IntlDateTimePatternGenerator_objects_free */ void IntlDateTimePatternGenerator_object_free(zend_object *object) { IntlDateTimePatternGenerator_object *dtpgo = php_intl_datetimepatterngenerator_fetch_object(object); zend_object_std_dtor(&dtpgo->zo); dtpgo->status = U_ZERO_ERROR; if (dtpgo->dtpg) { delete dtpgo->dtpg; dtpgo->dtpg = nullptr; } } /* }}} */ /* {{{ IntlDateTimePatternGenerator_object_create */ zend_object *IntlDateTimePatternGenerator_object_create(zend_class_entry *ce) { IntlDateTimePatternGenerator_object* intern; intern = (IntlDateTimePatternGenerator_object*)ecalloc(1, sizeof(IntlDateTimePatternGenerator_object) + zend_object_properties_size(ce)); zend_object_std_init(&intern->zo, ce); object_properties_init(&intern->zo, ce); intern->dtpg = nullptr; intern->status = U_ZERO_ERROR; intern->zo.handlers = &IntlDateTimePatternGenerator_object_handlers; return &intern->zo; } /* }}} */ /* {{{ proto void IntlDateTimePatternGenerator::__construct(string $locale) * IntlDateTimePatternGenerator object constructor. */ PHP_METHOD(IntlDateTimePatternGenerator, __construct) { zend_string *locale; zval *object; IntlDateTimePatternGenerator_object* dtpg = nullptr; if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &locale) == FAILURE) { return; } object = getThis(); dtpg = php_intl_datetimepatterngenerator_fetch_object(Z_OBJ_P(object)); dtpg->status = U_ZERO_ERROR; dtpg->dtpg = DateTimePatternGenerator::createInstance(Locale(ZSTR_VAL(locale)), dtpg->status); } /* }}} */ /* {{{ proto string IntlDateTimePatternGenerator::findBestPattern(string $skeleton) * Return the best pattern matching the input skeleton. */ PHP_METHOD(IntlDateTimePatternGenerator, findBestPattern) { zend_string *skeleton; zval *object; IntlDateTimePatternGenerator_object* dtpg = nullptr; if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &skeleton) == FAILURE) { return; } object = getThis(); dtpg = php_intl_datetimepatterngenerator_fetch_object(Z_OBJ_P(object)); UnicodeString pattern = dtpg->dtpg->getBestPattern(UnicodeString(ZSTR_VAL(skeleton)), dtpg->status); std::string s; pattern.toUTF8String(s); RETURN_STRING(s.c_str()); } /* }}} */ ZEND_BEGIN_ARG_INFO_EX(arginfo_findBestPattern, 0, 0, 1) ZEND_ARG_INFO(0, skeleton) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo___construct, 0, 0, 1) ZEND_ARG_INFO(0, locale) ZEND_END_ARG_INFO() const zend_function_entry IntlDateTimePatternGenerator_functions[] = { PHP_ME(IntlDateTimePatternGenerator, __construct, arginfo___construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(IntlDateTimePatternGenerator, findBestPattern, arginfo_findBestPattern, ZEND_ACC_PUBLIC) PHP_FE_END }; /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(intl_dtpg) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "IntlDateTimePatternGenerator", IntlDateTimePatternGenerator_functions); ce.create_object = IntlDateTimePatternGenerator_object_create; IntlDateTimePatternGenerator_ce = zend_register_internal_class(&ce); memcpy(&IntlDateTimePatternGenerator_object_handlers, zend_get_std_object_handlers(), sizeof IntlDateTimePatternGenerator_object_handlers); IntlDateTimePatternGenerator_object_handlers.offset = XtOffsetOf(IntlDateTimePatternGenerator_object, zo); IntlDateTimePatternGenerator_object_handlers.clone_obj = NULL; //no clone support IntlDateTimePatternGenerator_object_handlers.dtor_obj = IntlDateTimePatternGenerator_object_dtor; IntlDateTimePatternGenerator_object_handlers.free_obj = IntlDateTimePatternGenerator_object_free; if(!IntlDateTimePatternGenerator_ce) { zend_error(E_ERROR, "Failed to register IntlDateTimePatternGenerator class"); return FAILURE; } return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(intl_dtpg) { return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(intl_dtpg) { php_info_print_table_start(); php_info_print_table_header(2, "intl_dtpg support", "enabled"); php_info_print_table_header(2, "intl_dtpg version", INTL_DTPG_VERSION); php_info_print_table_end(); } /* }}} */ /* {{{ intl_dtpg_functions[] */ const zend_function_entry intl_dtpg_functions[] = { PHP_FE_END }; /* }}} */ /* {{{ intl_dtpg_module_entry */ zend_module_entry intl_dtpg_module_entry = { STANDARD_MODULE_HEADER, "intl_dtpg", intl_dtpg_functions, PHP_MINIT(intl_dtpg), PHP_MSHUTDOWN(intl_dtpg), NULL, NULL, PHP_MINFO(intl_dtpg), INTL_DTPG_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_INTL_DTPG #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE() #endif ZEND_GET_MODULE(intl_dtpg) #endif
      
      







まず、PHPオブジェクトのライフの特定のフェーズで実行されるハンドラーを定義します。



IntlDateTimePatternGenerator_object_dtor -PHPオブジェクトデストラクタ。 何もする必要はありません。標準APIを呼び出します。

IntlDateTimePatternGenerator_object_free-空きメモリ。 重要なフェーズでは、メモリリークが発生しないようにすべてを慎重に行う必要があります。 構造をzend_object



zend_object



のデストラクタを呼び出して、ステータスをリセットし、C ++クラスのオブジェクトを破棄します。

IntlDateTimePatternGenerator_object_create-新しいオブジェクトのメモリ割り当て。 コードは、intl拡張機能のソースコードでスパイされています。

次に、クラスのメソッドを定義します。

PHP_METHOD(IntlDateTimePatternGenerator、__ construct) -コンストラクター、新しいDateTimePatternGenerator



ます。

ここで、 zend_parse_parametersでは、文字列をzend_string



オブジェクトの形式で取得し、大きな「S」がzend_parse_parametersで示されています 。 これはPHP 7の革新です。しかし、以前の拡張機能で見たように、小さな「s」を指定し、Cスタイルの文字列とその長さを個別に取得する古い方法も機能します。

PHP_METHOD(IntlDateTimePatternGenerator、findBestPattern) -ここでは、ICUライブラリのクラスメソッドが呼び出されます。

以下は、クラスメソッドのパラメーターを決定するためのマクロのセットです。 zend_API.h



ファイル内のこれらのマクロのパラメーターの名前によって、それらの意味を理解できます。

zend_function_entry構造体は、クラスメソッドを指定します。 以前に定義されたパラメーターセットとフラグは、 PHP_MEマクロに渡されます。 この構造は、以下のクラスを登録するときに使用されます。

PHP_MINIT_FUNCTION(intl_dtpg) -拡張機能が初期化されるときに呼び出されます。 ここでクラスが登録され、ハンドラーがライフフェーズを提供するために示されます。

PHP_MSHUTDOWN_FUNCTION(intl_dtpg) -シャットダウン時に何もすることがない場合、単にSUCCESS



返すか、またはzend_module_entryで以下を指定することはできません。NULLを指定しNULL





PHP_MINFO_FUNCTION(intl_dtpg) -拡張情報をphpinfo()出力に追加します

再びzend_function_entryですが、今回は空です-この拡張では関数を定義しません。

zend_module_entry-ここでは拡張機能を初期化およびシャットダウンするメソッドを指定します。他の2つのNULL



はリクエストに関するもので、リクエストの初期化およびシャットダウン時には何もしません。



テスト



小さなテスト、パターンが生成されていることを確認してください:



001.phpt
 --TEST-- Check for intl_dtpg presence --SKIPIF-- <?php if (!extension_loaded("intl_dtpg")) print "skip"; ?> --FILE-- <?php $dtpg = new IntlDateTimePatternGenerator('ru_RU'); $ruPattern = $dtpg->findBestPattern('MMMMd'); $dtpg = new IntlDateTimePatternGenerator('en_US'); $enPattern = $dtpg->findBestPattern('MMMMd'); echo $ruPattern . ';' . $enPattern; ?> --EXPECT-- d MMMM;MMMM d
      
      







組み立てとテスト



 phpize && ./configure && make make test
      
      







valgrind-メモリリークの拡張機能を確認する



メモリリークについては、 intl_dtpg拡張機能を確認してください。 これを行うには、拡張フォルダーにテストiniファイルを作成します。



test-php.ini
 extension=modules/intl_dtpg.so
      
      







phpファイルをテストします。

test.php
 <?php $dtpg = new IntlDateTimePatternGenerator('ru_RU'); $ruPattern = $dtpg->findBestPattern('MMMMd'); $dtpg = new IntlDateTimePatternGenerator('en_US'); $enPattern = $dtpg->findBestPattern('MMMMd'); echo $ruPattern . ';' . $enPattern . "\n";
      
      







私たちはチェックします:



 valgrind php -c test-php.ini test.php
      
      





==30326== HEAP SUMMARY:

==30326== in use at exit: 478,022 bytes in 2,151 blocks

==30326== total heap usage: 22,863 allocs, 20,712 frees, 4,718,469 bytes allocated

==30326==

==30326== LEAK SUMMARY:

==30326== definitely lost: 0 bytes in 0 blocks

==30326== indirectly lost: 0 bytes in 0 blocks

==30326== possibly lost: 1,076 bytes in 14 blocks

==30326== still reachable: 476,946 bytes in 2,137 blocks

==30326== of which reachable via heuristic:

==30326== newarray : 30,416 bytes in 74 blocks

==30326== suppressed: 0 bytes in 0 blocks









悪くないようです。



実験するために、オブジェクトの破壊をコメントアウトします



IntlDateTimePatternGenerator_object_free IntlDateTimePatternGenerator_object_free



DateTimePatternGenerator







 /* {{{ IntlDateTimePatternGenerator_objects_free */ void IntlDateTimePatternGenerator_object_free(zend_object *object) { IntlDateTimePatternGenerator_object *dtpgo = php_intl_datetimepatterngenerator_fetch_object(object); zend_object_std_dtor(&dtpgo->zo); dtpgo->status = U_ZERO_ERROR; // if (dtpgo->dtpg) { // delete dtpgo->dtpg; // dtpgo->dtpg = nullptr; // } } /* }}} */
      
      





私たちはチェックします:



 valgrind php -c test-php.ini test.php
      
      





==411== HEAP SUMMARY:

==411== in use at exit: 770,710 bytes in 2,477 blocks

==411== total heap usage: 22,863 allocs, 20,386 frees, 4,718,469 bytes allocated

==411==

==411== LEAK SUMMARY:

==411== definitely lost: 5,232 bytes in 2 blocks

==411== indirectly lost: 287,456 bytes in 324 blocks

==411== possibly lost: 1,076 bytes in 14 blocks

==411== still reachable: 476,946 bytes in 2,137 blocks

==411== of which reachable via heuristic:

==411== newarray : 30,416 bytes in 74 blocks

==411== suppressed: 0 bytes in 0 blocks







「完全に失われた」線と「間接的に失われた」線は明らかに漏れを示しています。



おわりに



APIのドキュメントとネーミングには、多くの要望が残っていると言いたいです。 「Hello、world」よりも複雑なものを書く必要がある場合は、PHPのソースコードと組み込みの拡張機能を調べる必要があります。



All Articles