1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-23 23:32:16 +01:00
Files
archived-doc-ru/reference/ffi/examples.xml
2026-01-18 22:00:53 +00:00

380 lines
9.1 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: e14fdcab82e89bfb4ee221b1de9f4764c93abcf5 Maintainer: rjhdby 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>Базовая работа с модулем FFI</title>
<simpara>
Перед погружением в детали API-интерфейса модуля FFI, давайте рассмотрим
несколько примеров упрощённой работы API модуля FFI
в стандартных задачах.
</simpara>
<note>
<simpara>
Для ряда этих примеров потребуется
библиотека <filename>libc.so.6</filename>. Они не будут
работать в системах, где библиотека недоступна.
</simpara>
</note>
<example xml:id="ffi.examples.function">
<title>Вызов функции из общей библиотеки</title>
<programlisting role="php">
<![CDATA[
<?php
// Создаём объект FFI, загружаем библиотеку libc и экспортируем функцию printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // Это стандартная декларация в языке C
"libc.so.6"
);
// Вызываем функцию printf()
$ffi->printf("Привет, %s!\n", "мир");
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Привет, мир!
]]>
</screen>
</example>
<note>
<simpara>
Обратите внимание, что для отдельных функций языка C требуются конкретные
соглашения о вызовах, например: <literal>__fastcall</literal>,
<literal>__stdcall</literal> или <literal>,__vectorcall</literal>.
</simpara>
</note>
<example xml:id="ffi.examples.structure">
<title>Вызов функции и возврат структуры через аргумент</title>
<programlisting role="php">
<![CDATA[
<?php
// Создаём привязку 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"
);
// Создаём структуры данных языка C
$tv = $ffi->new("struct timeval");
$tz = $ffi->new("struct timezone");
// Вызываем функцию gettimeofday()
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));
// Получаем доступ к полю структуры данных языка C
var_dump($tv->tv_sec);
// Выводим структуру данных
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>Доступ к существующим переменным C</title>
<programlisting role="php">
<![CDATA[
<?php
// Создаём FFI-объект, загружаем библиотеку libc и экспортируем переменную errno
$ffi = FFI::cdef(
"int errno;", // Это стандартная декларация в языке C
"libc.so.6"
);
// Выводим значение переменной errno
var_dump($ffi->errno);
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
int(0)
]]>
</screen>
</example>
<example xml:id="ffi.examples.variable-creating">
<title>Создание и модификация C-переменной</title>
<programlisting role="php">
<![CDATA[
<?php
// Создаём переменную языка C с типом int
$x = FFI::new("int");
var_dump($x->cdata);
// Простое присваивание
$x->cdata = 5;
var_dump($x->cdata);
// Непростое присваивание
$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>Работа с массивами языка C</title>
<programlisting role="php">
<![CDATA[
<?php
// Создаём структуру данных
$a = FFI::new("long[1024]");
// Работаем с ней как с обычным PHP-массивом
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>Работа с перечислениями языка 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>Callback-функции PHP</title>
<para>
Можно присвоить замыкание PHP переменной с типом «указатель» (pointer)
или передать замыкание как аргумент функции:
<example>
<title>Присваивание <classname>Closure</classname> языка PHP указателю функции языка 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 "Привет, мир 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 "Привет, мир 2!\n";
$zend->zend_write = $orig_zend_write;
echo "Привет, мир 3!\n";
?>
]]>
</programlisting>
&example.outputs;
<screen>
<![CDATA[
Привет, мир 1!
{
Привет, мир 2!
}
Привет, мир 3!
]]>
</screen>
</example>
Хоть это и работает, но эта функциональность
поддерживается не на каждой платформе с библиотекой libffi, не эффективна
и вызывает утечку ресурсов при завершении запросов.
<tip>
<simpara>
Поэтому рекомендуют минимизировать использование callback-функций PHP.
</simpara>
</tip>
</para>
</section>
<section xml:id="ffi.examples-complete">
<title>Комплексный пример 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("Привет, %s!\n", "мир");
?>
]]>
</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
-->