Experimenting around FP in PHP
Published: 2023-12-18 13:23:01

> **Warn**: in this Post, it's tried to use as much typing as possible also if sometimes this means to take some distance from official documentation 

The evolution of the PHP language has had an effective contribution from some powerful specifications:

- the [Callable](https://www.php.net/manual/en/language.types.callable.php)
- the [Anonymous Function](https://www.php.net/manual/en/functions.anonymous.php)
- the [Closure](https://www.php.net/manual/en/class.closure.php)

These are now enriched by new RFC:

- the [Anonymous Classes](https://www.php.net/manual/en/language.oop5.anonymous.php) 
- the [Arrow Functions](https://www.php.net/manual/en/functions.arrow.php)
- the [First Class Callable Syntax](https://www.php.net/manual/en/functions.first_class_callable_syntax.php)

> **Note**: These RFCs make possible a lot of different constructs that go further than what will be exposed in this Post: remember that the "White Rabbit hole" is deep!


## Callable, Anonymous Function, Closure, and FP!

***Callables*** are generally used as the main type hint to define callbacks: a summary of how they can be defined/used can be seen in the [official documentation](https://www.php.net/manual/en/language.types.callable.php#118032). Introducing the ***__invoke*** function, even at the interface or anonymous class level, makes it possible to manage an object as a function transforming it into a Callable.

```php

class Butterfly {
  public function __invoke():void {echo "flying...";}
}
$butterfly = new Butterfly();
$butterfly(); // flying...

```
***Closure*** is the class used to represent anonymous functions: this kind of construct, also in the form of ***arrow*** function, is really useful not only as a callback, in place of a callable, but also more usage since the ability to capture a different scope or to simulate FP constructs such as [currying](https://en.wikipedia.org/wiki/Currying) like in the following code:

```php

class Person{
  private function __construct(
                     public readonly string $name, 
                     public readonly string $familyName,
                     public readonly int $age){}
    
    public static function create():\Closure
    {
     return 
          static fn(string $name):\Closure
          => static fn(string $familyName):\Closure
            => static fn(int $age):Person
             => new Person($name,$familyName,$age);
    }
}

$person = Person::create()('Frank')('Jamison')(50);

```
The introduction of ***First-Class Callable Syntax*** makes it possible to create Closure from any kind of function, defining a sort of ***function reference*** usable in places different from the definition (what follows reuse the example seen above)

```php

$personBuilder = Person::create(...);
$frank = $personBuilder()('Frank')('Jamison')(45);
$john= $personBuilder()('John')('Smith')(40);

```

## Arrays, arrays functions, and the anonymous functions

The use of anonymous functions is particularly useful when we refer to native functions on arrays: the potential is notable and makes the use of [loops superfluous](https://szymonkrajewski.pl/why-you-should-use-array-functions-instead-of-basic-loops/) as in the following code.

```php
$stock = [
  	['name' => 'Phone', 'qty' => 0],
  	['name' => 'Notebook', 'qty' => 1],
  	['name' => 'SDD Drive', 'qty' => 0],
 	['name' => 'HDD Drive', 'qty' => 3]
];

$inStock = array_filter($stock, static fn($item) => $item['qty'] > 0);
```

Native functions on arrays bring out the functional world when it comes down to it to the ***fold operation*** (the [array_reduce](https://www.php.net/manual/en/function.array-reduce.php) function) that allows us to be a point on which to build other fundamental functions such as ***map*** and ***filter***:

```php

/**
 *
 *@template T
 *@template R
 *@param array<T> $data
 *@param callable(T):R $mapper
 *@return array<R>
 *
 */
function map(array $data, callable $mapper):array
{
 return array_reduce($data, 
/** @param T $element */ 
function(array $accumulator, $element) use ($mapper)
             {
  			  $accumulator[] = $mapper($element);
			  return $accumulator;
			}, []);
}

/**
 *
 *@template T
 *@param array<T> $data
 *@param callable(T):bool $predicate
 *@return array<T>
 *
 */
function filter(array $data, callable $predicate):array
{
 return array_reduce($data, 
/** @param T $element */ 
function(array $accumulator, $element)use($predicate){					  
      if($predicate($element)){	  
        $accumulator[]=$element;
      } 
 return $accumulator;},[]);
}

```

The improved performance on arrays, starting from PHP 7.X, and the handling of anonymous functions are convenient from both a performance and memory consumption point of view although the practice of only using arrays sometimes doesn't make you consider the multiple benefits of alternative data structures.

Anonymous functions and closures are easy to distinguish given the ***use clause*** that allows you to capture elements from outside the given anonymous function. The value of the captured element is defined when the closure is declared and cannot be changed. 

```php

class Product{ ... }    

final class PriceRange {

   private function __construct(private float $minimumValue,
                                private float $maximumValue){}
	
	public static function of(
                     float $minimumValue, 
                     float $maximumValue): PriceRange{
	 return new PriceRange($minimumValue,$maximumValue);
	}
	
    public function priceFilter():\Closure{
        return fn(Product $value)=> 
               $value->price() >= $this->minimumValue 
		                     &&
               $value->price() < $this->maximumValue;
    }
}

/** @var array<Product> $prodcuts */
$products = [ ... ];

$range = PriceRange::of(5.0,10.0);

array_filter($products, $range->priceFilter());

```

Closures are still handy in design where you want to isolate the visibility of data, always in the light of the FP paradigm, as in the following example.

```php

/** @return \Closure():int */
function rndNumber():\Closure{
    return fn()=> rand(0,getrandmax()-1);
}

/** @return \Closure():int */
function rndConstant():\Closure{
    $constant = rand(0,getrandmax()-1);
    return fn()=> $constant; 
}

$rnd1 = rndNumber();
$c1 = rndConstant();
$c2 = rndConstant();

echo $rnd1(); // 505035335
echo $rnd1(); // 1353685165
echo $c1();   // 2030702172
echo $c1();   // 2030702172

```

These possibilities are also useful in approaching internal domain-specific languages (***DSL***) or adopting the ***higher-order function*** (in FP slang): the [Loan](https://www.oreilly.com/library/view/design-patterns-and/9781786463593/56585929-d828-45ce-9a91-648ad0dd4823.xhtml) Pattern and the [Execute Around](https://www.dontpanicblog.co.uk/2020/11/28/execute-around-idiom-in-java/) Pattern are examples of this concept.

```php
//
//Example of Execute-Around...
// ...also used in DSL definition for nested-dsl
//
 MailSender::Send(
        fn(Mail $config):Mail=>
	        $config
                    ->From("john.black@kmail.com")
                    ->To("jack.white@jmail.com")
                    ->Subject("Test message")
                    ->Body("Hello World!")
        );

//
// Example of Load Pattern
//
class ToyBox{

   ...

    /**
     * 
     * @param \Closure(ToyBox):ToyBox $boxFillerPolicy
     * @param \Closure(ToyBox):ToyBox $playActions
     * @return \Closure():void
     */
    public static final function play(\Closure $boxFillerPolicy, \Closure $playActions):\Closure
    {
        return function()use($boxFillerPolicy,$playActions):void{   
                  $box = new ToyBox();
                  $box->Open();
                  try{
                      $box = $boxFillerPolicy($box);
                      $box = $playActions($box);
                  }finally{
                      $box->Close()
                          ->CleanUpToys();
                  }
        };
    }

    ...

    public function nextToy():ToyBox{ ... }
    public function addToy(string $toyName):ToyBox{ ... }    
}

function Usage():void{
        $refill = fn(ToyBox $box):ToyBox
           =>$box
             ->addToy("lego")
             ->addToy("mechano")
             ->addToy("laser"); };
        
        $play = fn(ToyBox $box):ToyBox{
          => $box
            ->nextToy()
            ->nextToy()
            ->nextToy(); };
          
        $playSession = ToyBox::play($refill, $play);       
        $playSession();

```

## The Scope element in Closures

Closures can refer to different scopes than those in which they were created thanks to the ***bind*** functions. The possibilities of closures become considerable and they could replace the use of ***Reflection*** since they can access the private state of objects: this, however, has limitations in the presence of static analysis infrastructures such as PHPStan and PSALM which highlight *abuses of closures* as in the following example.

```php

class SimpleClass { 
    private int $privateData = 2; 
}

$simpleClosure = function():int {return $this->privateData;};
$instance = new SimpleClass();
$resultClosure = \Closure::bind(
                       $simpleClosure, 
                       $instance, 
                       SimpleClass::class);

echo $resultClosure==false?-1:$resultClosure();

...
//
//PSALM Output
//  
// ERROR: InvalidScope - Invalid reference to $this in a 
//          non-class context
// INFO: MixedInferredReturnType - Could not verify the  return 
// type 'int' for...
//

```
It's however possible to find ways to overcome these problems and exploit appropriately the potential of the closures from the outside of a class. A possible trick is to define a ***bridge operation*** (a protected function, also *static* if needed) to use when the Closure is created, as follows:

```php

class SimpleClass {
    private int $privateData = 2;
    protected final function data():int{ 
          return $this->privateData;
    }    
}

$instance = new SimpleClass();

// @phpstan-ignore return.unusedType
$accessTo = fn (string $bridgeOperation): ?\Closure
   =>
    \Closure::bind(
        function(SimpleClass $instance) use ($bridgeOperation): int{
            /** @var callable():int $operation */ 
            $operation = [$instance,$bridgeOperation];
            return $operation();
        },
        NULL,
        SimpleClass::class);

/** @var null|\Closure(SimpleClass):int $resultClosure **/
$resultClosure = $accessTo("privateData");

echo ($resultClosure===null?-1:$resultClosure($instance)); // 2

```

This approach seems more verbose but we can make it reusable and it passes static analysis given also more strong typing. It's also an example of how we can approach the FP concept of [Optics](https://medium.com/@gcanti/introduction-to-optics-lenses-and-prisms-3230e73bfcfe).

## Conclusion

The importance of the exposed specifications is not only in having introduced types for the different elements but it's also in the new design possibilities. They have also brought PHP even closer to natively approaching Functional Programming: so it's important to study and experiment also with static analysis enabled! It is worth noticing that with PHP you can approach FP both in a more function-oriented way or in a more object-oriented way using generics and advanced techniques thanks also to PHPStan or PSALM.

## To Go Furter

More elements need to be considered, here not exposed as for the design consequences of ***read-only*** constructs or the ***Generators***, but also if not adopted, it's useful to consider these concepts to enrich our ability to design Clean Software! 

Other resources allow the adoption of functional idioms/constructs and to study the concepts and approaches presented in this post: so... Happy Learn!

- https://www.infoq.com/articles/php7-function-improvements/
- https://github.com/fp4php/functional
- https://github.com/haskellcamargo/php-partial-function-application
- https://github.com/marcosh/lamphpda
- https://github.com/phunkie/phunkie
- https://github.com/functional-php
- https://github.com/widmogrod/php-functional
- https://github.com/loophp/collection
- https://leanpub.com/thinking-functionally-in-php
- https://www.phparch.com/books/functional-programming-in-php/
- https://link.springer.com/book/10.1007/978-1-4842-2958-3