ranvis/mecab

使用 FFI 的 MeCab 绑定

v0.3.3 2024-02-03 07:17 UTC

This package is auto-updated.

Last update: 2024-09-03 08:35:56 UTC


README

使用 FFI 的 MeCab 绑定。

许可

BSD 2-Clause License

此库包含部分 MeCab 接口定义,该定义根据BSD 3-Clause License授权。

安装

首先确保您已启用PHP中捆绑的FFI扩展。然后执行Composer命令

composer require "ranvis/mecab:^0.3"

确保您已将MeCab 0.996(或更高兼容版本)及其字典安装在您的系统上。在Windows和一些Linux发行版中,应该有预构建的包。

最后但同样重要的是,如果您打算在非CLI环境(如Web服务器)中使用此库,必须在SAPI使用的系统INI配置中将ffi.enable=true设置为默认受限的ffi.enable=preload

示例用法

use Ranvis\MeCab;

require_once __DIR__ . '/vendor/autoload.php';

$mecab = new MeCab\Env(); // libmecab.{so,dll} should be in the PATH directory
//$mecab = new MeCab\Env('libmecab.so.2'); // or libmecab.so.2 in it
//$mecab = new MeCab\Env('/usr/lib64/libmecab.so.2'); // or specify explicitly
var_dump($mecab->getVersion());

$tagger = $mecab->tagger();
//$tagger = $mecab->tagger(['--rcfile', '/path/to/mecabrc']);

foreach ($tagger->getDictionaryInfo() as $info) {
    $name = $info->getFileName();
    $name = substr($name, strlen(dirname($name, 2)));
    printf("Dictionary: %s, Version: %d, Encoding: %s\n", $name, $info->getVersion(), $info->getCharset());
}

$headNode = $tagger->parseToNode("メカブはおやつに入りますか?");
foreach ($headNode as $node) {
    echo $node->surface() . ": " . $node->feature() . "\n";
}

预加载动态库

使用FFI扩展通过脚本加载动态库与原生PHP扩展相比有少量开销。这可以通过使用FFI的预加载功能来缓解。通过预加载,类似守护进程的SAPI(如FPM)可以预处理库的初始化并在之后重用它。

使用ffi.preload预加载

要使用此功能,我们首先需要为MeCab生成一个头文件。运行捆绑的gen_mecab_preloader命令并指定目标(以及MeCab库名称/路径)。

$ mkdir ffi_preload.d
$ vendor/bin/gen_mecab_preloader ffi_preload.d/mecab.h /path/to/libmecab.so
Generated: ffi_preload.d/mecab.h

然后设置ffi.preload ini值以指向该文件。(如果此库有较大更新,可能需要重新生成头文件。)

现在为了检查它是否工作,我们使用CLI运行以下脚本。注意,现在使用MeCab\Env的静态方法MeCab\Env::fromScope()而不是构造函数来实例化,以利用预加载。

$ cat <<'END' > preload_test.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use Ranvis\MeCab;

$mecab = MeCab\Env::fromScope();
var_dump($mecab->getVersion());
END
$ php -d ffi.preload=ffi_preload.d/*.h preload_test.php
string(5) "0.996"

如果您的PHP以类似FPM的守护进程方式运行,则重启守护进程以生效。

使用opcache.preload预加载

注意:在Windows上不支持OPcache的预加载。(gh#4999

另一种预加载的方法是使用OPcache。OPcache还有预加载您经常使用的类的功能。如果未设置opcache.preload_user,或者在PHP 8.3及以后版本中将其设置为当前系统用户,FFI也可以在此步骤中初始化。(通常它不会被设置。)

在指定在opcache.preload ini值中的PHP脚本中,按如下方式调用MeCab\Env::preload()

<?php // preloader.php

require_once __DIR__ . '/vendor/autoload.php';

\Ranvis\MeCab\Env::preload('/path/to/libmecab.so');

然后在实际的脚本中,调用MeCab\Env::fromScope()进行实例化,就像前面的例子一样。

$ php -d opcache.preload=preloader.php preload_test.php

虽然这看起来比前面的方法简单,但每次OPcache的预加载触发时,系统临时目录都会无声地创建一个头文件;因为PHP 8.3及以后的FFI不允许预加载时的内存接口定义。