PHP函数式编程高阶技巧PHP的函数式编程能力在近几个版本中不断增强。从闭包到箭头函数从map/filter/reduce到函数组合PHP的函数式编程越来越实用。今天说说一些进阶的函数式编程技巧。柯里化是把多参数函数转换成单参数函数链的过程。每个函数接受一个参数返回接受下一个参数的新函数。php// 柯里化实现function curry(callable $fn, ...$args): Closure{return function (...$newArgs) use ($fn, $args) {$allArgs array_merge($args, $newArgs);$ref new ReflectionFunction($fn);if (count($allArgs) $ref-getNumberOfRequiredParameters()) {return $fn(...$allArgs);}return curry($fn, ...$allArgs);};}// 普通函数function add(float $a, float $b, float $c): float{return $a $b $c;}// 柯里化$curriedAdd curry(add);$add5 $curriedAdd(5);$add5And10 $add5(10);echo $add5And10(20) . \n; // 35// 实用的柯里化例子function createSqlSelect(string $table, string $columns, string $where): string{return SELECT {$columns} FROM {$table} WHERE {$where};}$curriedSelect curry(createSqlSelect);$fromUsers $curriedSelect(users);$selectUsers $fromUsers(id, name, email);echo $selectUsers(status active) . \n;?部分应用是把多参数函数的部分参数固定下来生成新的函数php// 部分应用function partial(callable $fn, ...$fixed): Closure{return function (...$args) use ($fn, $fixed) {return $fn(...array_merge($fixed, $args));};}function formatMessage(string $prefix, string $message, string $suffix): string{return [{$prefix}] {$message} {$suffix};}$infoLog partial(formatMessage, INFO, );$errorLog partial(formatMessage, ERROR, );echo $infoLog(用户登录) . \n;echo $errorLog(数据库连接失败) . \n;?函数组合是函数式编程的核心模式。多个小函数组合成复杂函数php// 函数组合function compose(callable ...$fns): Closure{return function ($value) use ($fns) {return array_reduce($fns, fn($carry, $fn) $fn($carry), $value);};}// 管道操作从左到右组合function pipe(callable ...$fns): Closure{return function ($value) use ($fns) {foreach ($fns as $fn) {$value $fn($value);}return $value;};}// 基础处理函数$trim fn(string $s): string trim($s);$lower fn(string $s): string strtolower($s);$removeSpaces fn(string $s): string preg_replace(/\s/, -, $s);$truncate fn(string $s): string substr($s, 0, 50);$removeSpecial fn(string $s): string preg_replace(/[^a-z0-9\-]/, , $s);// 组合成slug生成器$makeSlug pipe($trim,$lower,$removeSpaces,$removeSpecial,$truncate);echo $makeSlug( Hello World! This is a LONG title ) . \n;// 数据管道$processOrders pipe(fn(array $orders) array_filter($orders, fn($o) $o[status] paid),fn(array $orders) array_map(fn($o) $o[amount], $orders),fn(array $amounts) array_sum($amounts),fn(float $total) round($total, 2),fn(float $total) 已支付总额: {$total}元);$orders [[id 1, amount 100, status paid],[id 2, amount 250, status pending],[id 3, amount 80, status paid],];echo $processOrders($orders) . \n;?Either和Maybe是函数式编程中处理错误和空值的方式php// Maybe 模式class Maybe{private mixed $value;private bool $hasValue;private function __construct(mixed $value, bool $hasValue){$this-value $value;$this-hasValue $hasValue;}public static function just(mixed $value): self{return new self($value, true);}public static function nothing(): self{return new self(null, false);}public static function of(mixed $value): self{return $value null ? self::nothing() : self::just($value);}public function map(callable $fn): self{if (!$this-hasValue) return $this;return self::of($fn($this-value));}public function flatMap(callable $fn): self{if (!$this-hasValue) return $this;return $fn($this-value);}public function getOrDefault(mixed $default): mixed{return $this-hasValue ? $this-value : $default;}public function isPresent(): bool{return $this-hasValue;}}// 用法示例function findUser(int $id): Maybe{$users [1 张三, 2 李四];return Maybe::of($users[$id] ?? null);}$result findUser(1)-map(fn($name) strtoupper($name))-map(fn($name) Hello, $name!)-getOrDefault(默认用户);echo $result\n;$result2 findUser(999)-map(fn($name) strtoupper($name))-getOrDefault(未找到用户);echo $result2\n;?不可变数据结构是函数式编程的重要概念。PHP的对象默认是引用传递但可以用readonly类实现不可变性php// readonly类PHP8.1readonly class Point{public function __construct(public float $x,public float $y) {}public function withX(float $x): self{return new self($x, $this-y);}public function withY(float $y): self{return new self($this-x, $y);}public function add(self $other): self{return new self($this-x $other-x, $this-y $other-y);}public function distance(self $other): float{$dx $this-x - $other-x;$dy $this-y - $other-y;return sqrt($dx * $dx $dy * $dy);}}$p1 new Point(0, 0);$p2 new Point(3, 4);echo 距离: . $p1-distance($p2) . \n;$moved $p1-withX(10);echo 移动后: ({$moved-x}, {$moved-y})\n;echo 原始: ({$p1-x}, {$p1-y})\n;?PHP的函数式编程虽然没有Haskell或Scala那么纯粹但利用好闭包、高阶函数和不可变数据结构也能写出清晰、可测试的函数式风格代码。关键是要掌握pipe/compose、map/filter/reduce这些核心工具以及Maybe这类处理副作用的模式。