functional-php / trampoline
PHP 的 Trampoline 实现。
Requires
- php: >=5.6.0
Requires (Dev)
- atoum/atoum: *
This package is auto-updated.
Last update: 2024-09-21 20:41:39 UTC
README
Trampolines 是一种技术,用于在递归调用时避免调用栈溢出。这是因为 PHP 不执行尾调用优化。
有关尾调用优化(或 TCO)的更多信息,您可以阅读: http://stackoverflow.com/questions/310974/what-is-tail-call-optimization#answer-310980
有关 Trampolines 以及递归的整体更深入的定义,我推荐您阅读 http://blog.moertel.com/posts/2013-06-12-recursion-to-iteration-4-trampolines.html,该文使用 Python,但应该很容易理解。
安装
composer require functional-php/trampoline
基本用法
如果我们有以下递归函数
<?php function factorial($n, $acc = 1) { return $n <= 1 ? $acc : factorial($n - 1, $n * $acc); }; echo factorial(5); // 120
我们只需要简单地将递归调用替换为对 bounce
函数的调用
<?php use FunctionalPHP\Trampoline as T; function factorial($n, $acc = 1) { return $n <= 1 ? $acc : T\bounce('factorial', $n - 1, $n * $acc); }; echo T\trampoline('factorial', 5); // 120
bounce
和 trampoline
函数接受 PHP 认为是有效的 callable
任何内容。
trampoline
函数还将接受由 bounce
创建的 Trampoline
实例,但在这种情况下将忽略任何参数。
辅助函数
如果您喜欢这种风格,也可以静态调用全局命名空间中的任何函数
<?php use FunctionalPHP\Trampoline\Trampoline; echo Trampoline::factorial(5); // 120 echo Trampoline::strtoupper('Hello!'); // HELLO!
但是,这不会对命名空间内的函数起作用。
如果您想使用 trampoline 有一个现成的可调用函数,可以使用 trampoline_wrapper
辅助函数。它将创建一个包装函数,为您调用 trampoline
并返回结果。
<?php use FunctionalPHP\Trampoline as T; function factorial($n, $acc = 1) { return $n <= 1 ? $acc : T\bounce('factorial', $n - 1, $n * $acc); }; $fact = T\trampoline_wrapper('factorial'); echo $fact(5); // 120
替代方法
该库还包含一个替代实现,基于参数队列而不是 trampoline 运行尾递归函数,从而避免栈溢出风险。
您需要将 $this
变量用作递归函数。以下是使用第二种方法的阶乘示例。
<?php use FunctionalPHP\Trampoline as T; $fact = T\pool(function($n, $acc = 1) { return $n <= 1 ? $acc : $this($n - 1, $n * $acc); }); echo $fact(5); // 120
目前,仅支持匿名函数(即 Closure
类的实例)。但一旦 PHP 7.1 发布,您将能够使用任何可调用项。
从性能的角度来看,两种方法之间没有可测量的差异。
测试
您可以使用以下命令运行库的测试套件
composer test
测试报告将在 reports
目录中可用。
贡献
除了潜在的错误之外,不应该有太多要贡献的内容,但任何形式的贡献都受到欢迎!不要犹豫,提出问题或提交拉取请求。