La fonction FFI (Interface de fonction étrangère) de PHP nous permet d'appeler directement les fonctions dans le langage C, élargissant considérablement les scénarios d'application de PHP. Grâce à ffi :: cdef () , nous pouvons cartographier les déclarations de fonction dans le langage C en code PHP, réalisant ainsi l'opération efficace sous-jacente.
Cependant, un problème commun lors de l'utilisation de ffi :: cdef () est que si la déclaration de type C ne correspond pas au type dans la bibliothèque réelle, le programme peut s'écraser et même directement le processus PHP. Ce type de crash est généralement difficile à déboguer, et il n'est pas facile de détecter la cause spécifique.
Cet article combinera des exemples pour illustrer comment dépanner et gérer de tels accidents.
Ffi :: Cdef () est utilisé pour définir la signature de type et de fonction du langage C, telles que:
<?php
$ffi = FFI::cdef("
int printf(const char *format, ...);
");
$ffi->printf("Hello, %s!\n", "world");
?>
Ce code déclare la fonction printf de C à PHP, puis peut l'appeler.
Supposons que vous ayez une telle bibliothèque C, la signature de la fonction est la suivante:
// C Déclaration de fonction du langage
void process_data(const char *data, size_t len);
Lorsque vous le définissez en php, il a été écrit comme:
<?php
$ffi = FFI::cdef("
void process_data(const char *data, int len);
");
$ffi->process_data("example", 7);
?>
Notez que le deuxième paramètre de C est size_t , qui est un entier long non signé (généralement 64 bits ou 32 bits, selon la plate-forme), et INT est écrit en PHP. Cette inadéquation de type peut entraîner un tronqué ou une interprétation mal interprétée des données lors du passage des paramètres, ce qui entraînera éventuellement le crash du programme.
Lorsque vous utilisez FFI :: CDEF () , assurez-vous de vous référer aux fichiers d'en-tête des bibliothèques officielles ou tierces pour maintenir les déclarations de type complètement cohérentes. Portez une attention particulière aux types de données courants suivants:
size_t correspond à size_t dans PHP FFI, ne l'écrivez pas par erreur en int ou unsigned int .
Le type de pointeur doit être écrit correctement, tel que const char * .
La déclaration de structure doit correspondre exactement.
PHP FFI prend en charge Size_T et doit être utilisé directement:
<?php
$ffi = FFI::cdef("
void process_data(const char *data, size_t len);
");
?>
Cela évite la décalage de type sur les plates-formes 32/64 bits.
Si possible, le chargement du contenu de l'en-tête C directement au lieu de déclarations manuscrites peut réduire les erreurs:
<?php
$ffi = FFI::cdef(file_get_contents("your_lib.h"), "your_lib.so");
?>
Utilisez Strace ou GDB pour suivre les processus PHP et localiser les points de crash.
Simplifiez les déclarations de fichiers d'en-tête C et les appels de test étape par étape.
Remarquez la différence de size_t et d'autres types de taille sur différentes plates-formes (Linux / Windows / MacOS).
<?php
$ffi = FFI::cdef("
void process_data(const char *data, size_t len);
");
$data = "example";
$ffi->process_data($data, strlen($data));
?>
Cela empêchera les accidents causés par l'incohérence du type.
Résumé: PHP FFI est puissant, mais il est nécessaire de s'assurer que la déclaration de type C est complètement cohérente, en particulier la correspondance entre les types entiers et les types de pointeurs. Lors de la rencontre d'un crash, la priorité est donnée à la vérification de la définition de type dans ffi :: cdef () pour éviter les erreurs d'exécution causées par la non-concordance de type.