mirror of
https://github.com/php/doc-fr.git
synced 2026-03-23 22:52:18 +01:00
335 lines
7.9 KiB
XML
335 lines
7.9 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<!-- EN-Revision: e14fdcab82e89bfb4ee221b1de9f4764c93abcf5 Maintainer: pierrick Status: ready -->
|
|
<!-- Reviewed: no -->
|
|
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="ffi.examples">
|
|
&reftitle.examples;
|
|
<section xml:id="ffi.examples-basic">
|
|
<title>Utilisation basique de FFI</title>
|
|
<simpara>
|
|
Avant de plonger dans les détails de l'API FFI, jetons un coup d'œil à quelques exemples
|
|
démontrant la simplicité d'utilisation de l'API FFI pour les tâches courantes.
|
|
</simpara>
|
|
<note>
|
|
<simpara>
|
|
Certains de ces exemples requièrent <filename>libc.so.6</filename> et
|
|
ne fonctionneront donc pas sur les systèmes où cette bibliothèque n'est pas disponible.
|
|
</simpara>
|
|
</note>
|
|
<example xml:id="ffi.examples.function">
|
|
<title>Appel d'une fonction à partir d'une bibliothèque partagée</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// crée un objet FFI, en chargeant la libc et en exportant la fonction printf()
|
|
$ffi = FFI::cdef(
|
|
"int printf(const char *format, ...);", // Déclaration C régulière
|
|
"libc.so.6");
|
|
// appelle la fonction printf() de C
|
|
$ffi->printf("Hello %s!\n", "world");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Hello world!
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<note>
|
|
<simpara>
|
|
Il est à noter que certaines fonctions C nécessitent des conventions d'appel spécifiques, par exemple <literal>__fastcall</literal>,
|
|
<literal>__stdcall</literal> ou <literal>,__vectorcall</literal>.
|
|
</simpara>
|
|
</note>
|
|
<example xml:id="ffi.examples.structure">
|
|
<title>Appel d'une fonction, retournant une structure par l'intermédiaire d'un argument</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// crée la liaison gettimeofday()
|
|
$ffi = FFI::cdef("
|
|
typedef unsigned int time_t;
|
|
typedef unsigned int suseconds_t;
|
|
|
|
struct timeval {
|
|
time_t tv_sec;
|
|
suseconds_t tv_usec;
|
|
};
|
|
|
|
struct timezone {
|
|
int tz_minuteswest;
|
|
int tz_dsttime;
|
|
};
|
|
|
|
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
|
", "libc.so.6");
|
|
// crée les structures de données C
|
|
$tv = $ffi->new("struct timeval");
|
|
$tz = $ffi->new("struct timezone");
|
|
// appelle la fonction gettimeofday() de C
|
|
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));
|
|
// accède aux champs de la structure de données C
|
|
var_dump($tv->tv_sec);
|
|
// imprime toute la structure de données C
|
|
var_dump($tz);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs.similar;
|
|
<screen>
|
|
<![CDATA[
|
|
int(0)
|
|
int(1555946835)
|
|
object(FFI\CData:struct timezone)#3 (2) {
|
|
["tz_minuteswest"]=>
|
|
int(0)
|
|
["tz_dsttime"]=>
|
|
int(0)
|
|
}
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example xml:id="ffi.examples.variable-existing">
|
|
<title>Accès aux variables C existantes</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// crée un objet FFI, en chargeant la libc et en exportant la variable errno
|
|
$ffi = FFI::cdef(
|
|
"int errno;", // Déclaration C régulière
|
|
"libc.so.6");
|
|
// imprime la valeur errno de C
|
|
var_dump($ffi->errno);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
int(0)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example xml:id="ffi.examples.variable-creating">
|
|
<title>Création et modification de variables C</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// crée une nouvelle variable C de type int
|
|
$x = FFI::new("int");
|
|
var_dump($x->cdata);
|
|
|
|
// affectation simple
|
|
$x->cdata = 5;
|
|
var_dump($x->cdata);
|
|
|
|
// affectation composée
|
|
$x->cdata += 2;
|
|
var_dump($x->cdata);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
int(0)
|
|
int(5)
|
|
int(7)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<para>
|
|
<example xml:id="ffi.examples.array">
|
|
<title>Travailler avec des tableaux C</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// crée une structure de données en C
|
|
$a = FFI::new("long[1024]");
|
|
// modification de la structure comme avec un tableau PHP normal
|
|
for ($i = 0; $i < count($a); $i++) {
|
|
$a[$i] = $i;
|
|
}
|
|
var_dump($a[25]);
|
|
$sum = 0;
|
|
foreach ($a as $n) {
|
|
$sum += $n;
|
|
}
|
|
var_dump($sum);
|
|
var_dump(count($a));
|
|
var_dump(FFI::sizeof($a));
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
int(25)
|
|
int(523776)
|
|
int(1024)
|
|
int(8192)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</para>
|
|
<example xml:id="ffi.examples.enum">
|
|
<title>Travailler avec des enums en C</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$a = FFI::cdef('typedef enum _zend_ffi_symbol_kind {
|
|
ZEND_FFI_SYM_TYPE,
|
|
ZEND_FFI_SYM_CONST = 2,
|
|
ZEND_FFI_SYM_VAR,
|
|
ZEND_FFI_SYM_FUNC
|
|
} zend_ffi_symbol_kind;
|
|
');
|
|
var_dump($a->ZEND_FFI_SYM_TYPE);
|
|
var_dump($a->ZEND_FFI_SYM_CONST);
|
|
var_dump($a->ZEND_FFI_SYM_VAR);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
int(0)
|
|
int(2)
|
|
int(3)
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
</section>
|
|
<section xml:id="ffi.examples-callback">
|
|
<title>Fonctions de rappels</title>
|
|
<para>
|
|
Il est possible d'assigner une fermeture PHP à une variable native de type pointeur de fonction
|
|
ou de la passer comme argument de fonction :
|
|
<example>
|
|
<title>Assignation d'une <classname>Closure</classname> PHP à un pointeur de fonction C</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$zend = FFI::cdef("
|
|
typedef int (*zend_write_func_t)(const char *str, size_t str_length);
|
|
extern zend_write_func_t zend_write;
|
|
");
|
|
|
|
echo "Hello World 1!\n";
|
|
|
|
$orig_zend_write = clone $zend->zend_write;
|
|
$zend->zend_write = function($str, $len) {
|
|
global $orig_zend_write;
|
|
$orig_zend_write("{\n\t", 3);
|
|
$ret = $orig_zend_write($str, $len);
|
|
$orig_zend_write("}\n", 2);
|
|
return $ret;
|
|
};
|
|
echo "Hello World 2!\n";
|
|
$zend->zend_write = $orig_zend_write;
|
|
echo "Hello World 3!\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Hello World 1!
|
|
{
|
|
Hello World 2!
|
|
}
|
|
Hello World 3!
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
Bien que cela fonctionne, cette fonctionnalité n'est pas supportée par toutes les plateformes libffi, n'est pas efficace
|
|
et entraîne des fuites de ressources à la fin de la requête.
|
|
<tip>
|
|
<simpara>
|
|
Il est donc recommandé de minimiser l'utilisation des fonctions de rappels PHP.
|
|
</simpara>
|
|
</tip>
|
|
</para>
|
|
</section>
|
|
|
|
<section xml:id="ffi.examples-complete">
|
|
<title>Un exemple complet de PHP/FFI/preloading</title>
|
|
<informalexample>
|
|
<simpara><filename>php.ini</filename></simpara>
|
|
<programlisting role="ini">
|
|
<![CDATA[
|
|
ffi.enable=preload
|
|
opcache.preload=preload.php
|
|
]]>
|
|
</programlisting>
|
|
<simpara><filename>preload.php</filename></simpara>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
FFI::load(__DIR__ . "/dummy.h");
|
|
opcache_compile_file(__DIR__ . "/dummy.php");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
<simpara><filename>dummy.h</filename></simpara>
|
|
<programlisting role="c">
|
|
<![CDATA[
|
|
#define FFI_SCOPE "DUMMY"
|
|
#define FFI_LIB "libc.so.6"
|
|
|
|
int printf(const char *format, ...);
|
|
]]>
|
|
</programlisting>
|
|
<simpara><filename>dummy.php</filename></simpara>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
final class Dummy {
|
|
private static $ffi = null;
|
|
function __construct() {
|
|
if (is_null(self::$ffi)) {
|
|
self::$ffi = FFI::scope("DUMMY");
|
|
}
|
|
}
|
|
function printf($format, ...$args) {
|
|
return (int) self::$ffi->printf($format, ...$args);
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
<simpara><filename>test.php</filename></simpara>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$d = new Dummy();
|
|
$d->printf("Hello %s!\n", "world");
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</section>
|
|
</chapter>
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|