Zephir と PHP-CPP の学習および比較のために、UTF-8 の文字列関数の開発に取り組みました。今後、複数の関数や C 言語の例を追加してゆく予定です。
インストール
Zephir
ビルドツールをインストールした上で、git のリポジトリからビルドします。
git clone https://github.com/phalcon/zephir
cd zephir
./install -c
PHP-CPP
git clone https://github.com/CopernicaMarketingSoftware/PHP-CPP.git
cd PHP-CPP
sudo make install
Mac OS X の場合、Makefile を次のように修正しました。
INSTALL_PREFIX = /usr/local
LINKER_FLAGS = -shared -undefined dynamic_lookup
${PHP_SHARED_LIBRARY}: ...
... ${LINKER} ${PHP_LINKER_FLAGS} -Wl -o libphpcpp.so.$(SONAME)
プロジェクトのセットアップとビルド
Zephir
zephir init myproject
ビルドには zephir compile
を実行します。zephir build
はインストールも実行されます。
PHP-CPP
Your first extension のチュートリアルページから EmptyExtension.zip および EmptyExtension.tar.gz をダウンロードします。ビルドとインストールのために make および make install を実行します。
Mac OS X の場合、Makefile を次のように修正しました。
INI_DIR = /usr/local/etc/php/5.6/conf.d
COMPILER_FLAGS = -I /usr/local/include/ -I /usr/local/include/phpcpp -Wall -c -O2 -std=c++11 -fpic -o
LINKER_FLAGS = -shared -L /usr/local/lib
LINKER_DEPENDENCIES = -lphpcpp
C 言語
プロジェクトのセットアップには ext_skel
コマンドを使います。
cd /path/to/ext
./ext_skel --extname=helloworld
config.m4 の次の3行のコメントを解除します。
PHP_ARG_WITH(helloworld, for helloworld support,
Make sure that the comment is aligned:
[ --with-helloworld Include helloworld support])
Makefile の生成には phpize を実行します。make および make install でビルドおよびインストールを実行します。
phpize
./configure
make
make install
PHP 7.0 対応
zend_string API と smart_string が導入されました Upgrading PHP extensions from PHP5 to NG。また引数の解析のパフォーマンス改善のために Fast Parameter Parsing API が導入されました。
UTF-8 の仕様
Unicode 8.0 の3章 で定義されています (Table 3-7. Well-Formed UTF-8 Byte Sequences)。
コードポイント 1番目のバイト 2番目のバイト 3番目のバイト 4番目のバイト
U+0000 - U+007F 00 - 7F
U+0080 - U+07FF C2 - DF 80 - BF
U+0800 - U+0FFF E0 A0 - BF 80 - BF
U+1000 - U+CFFF E1 - EC 80 - BF 80 - BF
U+D000 - U+D7FF ED 80 - 9F 80 - BF
U+E000 - U+FFFF EE - EF 80 - BF 80 - BF
U+10000 - U+3FFFF F0 90 - BF 80 - BF 80 - BF
U+40000 - U+FFFFF F1 - F3 80 - BF 80 - BF 80 - BF
U+100000 - U+10FFFF F4 80 - 8F 80 - BF 80 - BF
拡張書記素クラスターの境界の仕様
旧字体や色違いの絵文字、梵字など、1つの文字が基底文字と結合記号の組み合わせで表現されることがあります。このような複数のコードポイントで構成される基本単位を拡張書記素クラスターと呼びます。拡張書記素クラスターの境界は UNICODE TEXT SEGMENTATION の仕様の Grapheme Cluster Boundary Rules で定義されます。
PCRE は拡張書記素クラスターをあらわすメタ文字の \X
を定義しており、(?>\PM\pM*)
と同等とのことです。
C 言語で書記素を1つずつ取り出して表示するコードの例は gist で公開しています。
文字とコードポイントの相互変換
C 言語
コードの例はこちらの記事をご参照ください。
文字数を求める
記事の公開時点では不正なバイト列は考慮しない状態です。
Zephir
namespace StrUtils;
function length(string str)
{
int bytesize;
int len, current, size;
uchar lead;
let bytesize = str->length();
let len = 0;
let current = 0;
let size = 0;
while bytesize > current {
let lead = str[current];
if lead < 0x80 {
let size = 1;
} elseif lead < 0xE0 {
let size = 2;
} elseif lead < 0xF0 {
let size = 3;
} elseif lead < 0xF5 {
let size = 4;
} else {
let size = 1;
}
let current += size;
let len++;
}
return len;
}
PHP-CPP
# include <phpcpp.h>
# include <string>
Php::Value length(Php::Parameters &params)
{
std::string str = params[0];
int pos;
unsigned char lead;
int size;
Php::Value len = 0;
for (pos = 0; pos < str.size(); pos += size) {
lead = str.at(pos);
if (lead < 0x80) {
size = 1;
} else if (lead < 0xE0) {
size = 2;
} else if (lead < 0xF0) {
size = 3;
} else {
size = 4;
}
len += 1;
}
return len;
}
extern "C" {
PHPCPP_EXPORT void *get_module()
{
static Php::Extension extension("strutils", "1.0");
extension.add("StrUtils\\length", length);
return extension;
}
}
C 言語
standard/html.c
で定義される php_next_utf8_char
を使うことができます。この関数は htmlspecialchars
の実装に使われています。コードの例はこちらの記事をご参照ください。