I find function overriding/overloading very helpful in non-OO code, and therefore present the following for your use:
(you can drop the pipes for nested calls in pre 8.5)
<?php
function overload( $p, $f, $override=false ) {
$types = str_replace( [ '(', ')','{','}' ], [ ',', '',',','' ], $p )
|> ( fn($x) => explode( ',', $x ) )
|> ( fn($x) => array_map( 'trim', $x ) )
|> array_filter(...);
if ( is_callable( $types[0] ) &&
! isset( $GLOBALS[ $types[0].'_overloaded' ] ) )
throw new Exception(
'overload function name not allowed:' . $types[0] );
$fn = '_';
if ( array_last( $types ) === '...' ) {
$fn = '.'; array_pop( $types ); }
$fn .= strtolower( join( '_', $types ) );if ( isset( $GLOBALS[$fn] ) && ! $override )
throw new Exception (
'overload function already exists:' . $p );
$GLOBALS[ $fn ] = $f;
if ( ! is_callable( $types[0] ) ) {
$fx = <<<'router'
function {fn}( ...$p ) {
$vt = []; foreach ( $p as $pp )
$vt[] = gettype( $pp );
$fn = '_{fn}_' . join( '_', $vt );
for (;;) {
if ( isset( $GLOBALS[ $fn ] ) ) {
try {
return $GLOBALS[ $fn ]( ...$p );
}
catch ( Exception $x) {
throw new Exception(
'overload function:' +
$fn + ': ' +
$x->getMessage() );
}
}
$fn[0] = '.'; //degenerate signature
if ( ( $i = strrpos( $fn, '_' ) ) === false )
break;
$fn = substr( $fn, 0, $i );
}
throw new Exception(
'no overload: {fn}(' . join( ', ', $vt) . ')' );
};
router;
eval( str_replace( '{fn}', $types[0], $fx ) );
$GLOBALS[ $types[0].'_overloaded' ] = true;
}
return true;
}
overload( 'add( integer, integer, integer )',
fn($a,$b,$c) => ($a + $b + $c).' from 3i form' );
overload( 'add( integer, ... )',
fn(...$i) => array_reduce( $i, fn($I, $i) => $I += $i, 0 ) .
' from integer degen form' );
overload( 'add( string, ... )',
fn(...$s) => array_reduce( $s, fn($a, $s) => $a .= $s, '' ) .' from string degen form' );
echo add( 1, 2 ) . '<br>';
echo add( 1, 2, 3 ) . '<br>';
echo add( '3', '+', 5, '=', 8);
?>
------------------------------------------------
output:
3 from integer degen form
6 from 3i form
3+5=8 from string degen form