ranvis / mecab
使用 FFI 的 MeCab 绑定
Requires
- php: >=8.0.0
- ext-ffi: *
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不允许预加载时的内存接口定义。