-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial translation in reference/ffi
- Loading branch information
1 parent
da5f25d
commit 04c1038
Showing
8 changed files
with
1,432 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,344 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- EN-Revision: 8859c8b96cd9e80652813f7bcf561432a5e9f934 Maintainer: leonardolara Status: ready --> | ||
|
||
<chapter xml:id="ffi.examples" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> | ||
&reftitle.examples; | ||
<section xml:id="ffi.examples-basic"> | ||
<title>Uso básico da FFI</title> | ||
<para> | ||
Antes de mergulhar nos detalhes da API da FFI, seguem abaixo alguns exemplos | ||
demonstrando a simplicidade de seu uso para tarefas regulares. | ||
</para> | ||
<note> | ||
<para> | ||
Alguns destes exemplos requerem o <filename>libc.so.6</filename> e por isso não | ||
funcionarão em sistemas onde ele não estiver disponível. | ||
</para> | ||
</note> | ||
<para> | ||
<example xml:id="ffi.examples.function"> | ||
<title>Chamando uma função de uma biblioteca compartilhada</title> | ||
<programlisting role="php"> | ||
<![CDATA[ | ||
<?php | ||
// cria o objeto FFI, carregando a libc e exportando a função printf() | ||
$ffi = FFI::cdef( | ||
"int printf(const char *format, ...);", // esta é uma declaração normal em C | ||
"libc.so.6"); | ||
// chama printf() da linguagem C | ||
$ffi->printf("Olá, %s!\n", "mundo"); | ||
?> | ||
]]> | ||
</programlisting> | ||
&example.outputs; | ||
<screen> | ||
<![CDATA[ | ||
Olá, mundo! | ||
]]> | ||
</screen> | ||
</example> | ||
</para> | ||
<note> | ||
<para> | ||
Observe que algumas funções de C precisam de convenções específicas de chamada, por exemplo <literal>__fastcall</literal>, | ||
<literal>__stdcall</literal> ou <literal>,__vectorcall</literal>. | ||
</para> | ||
</note> | ||
<para> | ||
<example xml:id="ffi.examples.structure"> | ||
<title>Chamando uma função e retornando uma estrutura através de um argumento</title> | ||
<programlisting role="php"> | ||
<![CDATA[ | ||
<?php | ||
// cria uma ligação a 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"); | ||
// cria estrutura de dados em C | ||
$tv = $ffi->new("struct timeval"); | ||
$tz = $ffi->new("struct timezone"); | ||
// chama a função C gettimeofday() | ||
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz))); | ||
// acessa campo da estrutura de dados C | ||
var_dump($tv->tv_sec); | ||
// exibe toda a estrutura de dados 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> | ||
</para> | ||
<para> | ||
<example xml:id="ffi.examples.variable-existing"> | ||
<title>Acessando variáveis C existentes</title> | ||
<programlisting role="php"> | ||
<![CDATA[ | ||
<?php | ||
// cria o objeto FFI, carregando a libc e exportando a variável errno | ||
$ffi = FFI::cdef( | ||
"int errno;", // esta é uma declaração normal em C | ||
"libc.so.6"); | ||
// exibe o errno de C | ||
var_dump($ffi->errno); | ||
?> | ||
]]> | ||
</programlisting> | ||
&example.outputs; | ||
<screen> | ||
<![CDATA[ | ||
int(0) | ||
]]> | ||
</screen> | ||
</example> | ||
</para> | ||
<para> | ||
<example xml:id="ffi.examples.variable-creating"> | ||
<title>Criando e modificando variáveis C</title> | ||
<programlisting role="php"> | ||
<![CDATA[ | ||
<?php | ||
// cria uma nova variável int em C | ||
$x = FFI::new("int"); | ||
var_dump($x->cdata); | ||
// atribuição simples | ||
$x->cdata = 5; | ||
var_dump($x->cdata); | ||
// atribuição composta | ||
$x->cdata += 2; | ||
var_dump($x->cdata); | ||
?> | ||
]]> | ||
</programlisting> | ||
&example.outputs; | ||
<screen> | ||
<![CDATA[ | ||
int(0) | ||
int(5) | ||
int(7) | ||
]]> | ||
</screen> | ||
</example> | ||
</para> | ||
<para> | ||
<example xml:id="ffi.examples.array"> | ||
<title>Trabalhando com arrays C</title> | ||
<programlisting role="php"> | ||
<![CDATA[ | ||
<?php | ||
// cria estrutura de dados C | ||
$a = FFI::new("long[1024]"); | ||
// trabalhando com ela como um array normal do 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> | ||
<para> | ||
<example xml:id="ffi.examples.enum"> | ||
<title>Trabalhando com enumerações 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> | ||
</para> | ||
</section> | ||
<section xml:id="ffi.examples-callback"> | ||
<title>Funções de retorno PHP</title> | ||
<para> | ||
É possível atribuir um closure do PHP a uma variável nativa do tipo ponteiro de função | ||
ou passá-lo como um argumento de função: | ||
<example> | ||
<title>Atribuindo um <classname>Closure</classname> PHP a um ponteiro de função 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 "Olá, Mundo 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 "Olá, Mundo 2!\n"; | ||
$zend->zend_write = $orig_zend_write; | ||
echo "Olá, Mundo 3!\n"; | ||
?> | ||
]]> | ||
</programlisting> | ||
&example.outputs; | ||
<screen> | ||
<![CDATA[ | ||
Olá, Mundo 1! | ||
{ | ||
Olá, Mundo 2! | ||
} | ||
Olá, Mundo 3! | ||
]]> | ||
</screen> | ||
</example> | ||
Embora isso funciona, esta funcionalidade não é suportada em todas as plataformas libffi, não é eficiente | ||
e apresenta vazamento de recursos ao final da requisição. | ||
<tip> | ||
<simpara> | ||
Portanto, é recomendado minimizar o uso de chamadas de retorno do PHP. | ||
</simpara> | ||
</tip> | ||
</para> | ||
</section> | ||
|
||
<section xml:id="ffi.examples-complete"> | ||
<title>Um exemplo completo de PHP/FFI/pré-carregamento</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("Olá, %s!\n", "mundo"); | ||
?> | ||
]]> | ||
</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 | ||
--> |
Oops, something went wrong.