PHPにおける数学式の解析を行う場合、自前で構文解析器を実装するのは非常に複雑です。JavaScriptエコシステムではwebpackがJavaScriptコードをAST形式に変換して処理するように、既存のライブラリを活用するのが効率的です。
PHPにおけるAST解析の実装例
PHPではnikic/php-parserライブラリが広く使用されています。以下に基本的な使用方法を示します。
composer require nikic/php-parser
AST構文木の生成
数式文字列をASTに変換する処理の実装例:
namespace App\Http\Controllers\Math;
use PhpParser\ParserFactory;
use PhpParser\NodeDumper;
class AstController {
public function parseExpression(string $expression) {
$code = <<<PHP_CODE
\$result = $expression;
PHP_CODE;
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try {
$ast = $parser->parse($code);
} catch (\Exception $e) {
throw new \RuntimeException("構文解析失敗: " . $e->getMessage());
}
$dumper = new NodeDumper;
return $dumper->dump($ast);
}
}
ASTトラバーサーによるノード操作
ASTの各ノードを巡回して演算子と数値を分離するカスタムビジター:
namespace App\Visitor;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Node;
class AstVisitor extends NodeVisitorAbstract {
private $values = [];
private $operators = [];
public function leaveNode(Node $node) {
if ($node instanceof Node\Scalar\LNumber) {
$this->values[] = $node->value;
}
if ($node instanceof Node\Expr\BinaryOp) {
$this->operators[] = $node->getType();
}
}
public function getValues(): array {
return $this->values;
}
public function getOperators(): array {
return $this->operators;
}
}
使用例
$parser = new AstController();
$astDump = $parser->parseExpression("((99 + 1)*4-1)");
// ビジターによるノード処理
$traverser = new NodeTraverser();
$visitor = new AstVisitor();
$traverser->addVisitor($visitor);
$processed = $traverser->traverse($parser->getAst());
print_r($visitor->getValues()); // [99, 1, 4, 1]
print_r($visitor->getOperators()); // ['BinaryOp_Plus', 'BinaryOp_Mul', 'BinaryOp_Minus']
このようにしてASTを解析することで、数式の要素を分解して処理することが可能になります。複雑な演算子やカスタム関数のサポートには、ノードタイプの判定処理を追加する必要があります。
その他の関連ツール
mathjs: JavaScriptベースの数学ライブラリpostcss-math: CSSにおける数式計算を可能にするPostCSSプラグインMicrosoft/tolerant-php-parser: PHPの代替パーサー実装