这篇文章的灵感很大程度上来自 Gina Banyard 在“FORUM PHP 2024”上的技术演讲:
让我们从一些同义词开始:
如果你用谷歌搜索“PHP monads”,其他概念会很快出现,比如函数式编程、绑定、堆栈,甚至深奥的数学(例如函子、幺半群)。
别害怕。
从本质上讲,Monad 是一种可以通过多种方式实现的模式。
当您要运行一些操作时,您可以像往常一样简单地定义自定义对象和助手。
那么,为什么要费心考虑替代概念呢?
恕我直言,这仍然是一个好问题,因为您需要保持效率,但经典方法存在常见的局限性:
Monad 可以更一致地处理可选(或尚不可用)值。
现代项目包含静态分析工具,但 PHP 异常没有类型化。
也就是说,工具无法检测函数签名中的异常,因此无法判断代码是否正确处理异常。
为了测试这一点,开发团队通常会编写功能测试,但通过静态分析进行早期检测会更可靠。
来源:“Les Exception:le trou dans la raquette du typepage”(fr)
使用 Monads,您在所有情况下都会获得一个类型化对象,例如自定义枚举情况(例如 FileErrors::AccessDenied),因此错误会在系统中键入。
构建强大的日志系统可能具有挑战性。复制字符串和调用很容易。
您可能会定义一个名为 log() 的自定义帮助程序,并在项目中的任何地方使用它,而不是对所有内容进行硬编码。
这旨在保持代码干燥,但可能不允许在特定情况下组合更复杂的函数。
函数式方法不包括使用这样的全局帮助器。相反,它宁愿实现一个 Monad 来包装其他函数:
final class LoggerMonad { public function __construct( public mixed $data, public array $logs = [], ) {} public function bind(callable $fn) { $resultLoggerMonad = $fn($this->data); return new LoggerMonad( $resultLoggerMonad->data, [...$this->logs, ...$resultLoggerMonad->logs], ); } } function loggify(callable $fn): Closure { return function ($value) use ($fn) { $name = (new ReflectionFunction($fn))->name; $log = [ 'Running '. $name .'('. var_export($value, true) .')' ]; return new LoggerMonad($fn($value), $log); }; }
然后,您可以像这样使用 loggify 包装器:
function add2(int $v): int { return $v + 2; } function square(int $v): int { return $v * $v; } function multi3(int $v): int { return $v * 3; } function logIt($value, callable ...$fns) { $logging_fns = array_map(loggify(...), $fns); $monad = new LoggerMonad($value); foreach ($logging_fns as $fn) { $monad = $monad->bind($fn); } return $monad; } print_r(logIt( 3, add2(...), square(...), multi3(...) ));
来源:“Monades simplement”,作者:Gina Banyard (fr)
??宝贝别伤害我
Monad 旨在包装值,可以是任何类型,包括对象和函数。
与任何其他包装系统一样,您会发现一个将此值作为输入的构造函数(〜类)以及一些根据您尝试实现的模式有其自己用途的方法。
但是,所有 Monad 都包含绑定函数。顾名思义,这是传递值(或回调)的地方。
无论这些回调中发生什么,monad 都会包装它,这似乎是装饰值和重构代码的强大方法。
这显然取决于实现,一开始很容易迷失。
但是,这种替代方法可以显着减少 if 块的数量,并使返回值更加一致:
final class LoggerMonad { public function __construct( public mixed $data, public array $logs = [], ) {} public function bind(callable $fn) { $resultLoggerMonad = $fn($this->data); return new LoggerMonad( $resultLoggerMonad->data, [...$this->logs, ...$resultLoggerMonad->logs], ); } } function loggify(callable $fn): Closure { return function ($value) use ($fn) { $name = (new ReflectionFunction($fn))->name; $log = [ 'Running '. $name .'('. var_export($value, true) .')' ]; return new LoggerMonad($fn($value), $log); }; }
来源:fp4php - monad
希望您现在对 PHP monad 有更多了解。
当然,您不应该仅仅为了项目而添加花哨的设计模式。
此外,虽然这是一个全新的范例,但很容易错过要点并专注于非常具体的方面,例如错误处理。
然而,发现新方法仍然令人耳目一新。我们需要跳出框框思考。
以上是PHP:单子的详细内容。更多信息请关注PHP中文网其他相关文章!