Completed
Pull Request — master (#24)
by Robbert
02:19
created

lambda::partialMerge()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5.073

Importance

Changes 5
Bugs 3 Features 2
Metric Value
c 5
b 3
f 2
dl 0
loc 18
ccs 12
cts 14
cp 0.8571
rs 8.8571
cc 5
eloc 11
nc 6
nop 3
crap 5.073
1
<?php
2
/*
3
 * This file is part of the Ariadne Component Library.
4
 *
5
 * (c) Muze <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace arc;
11
12
/**
13
 * Class lambda
14
 * Experimental functionality, may be removed later, use at own risk.
15
 * @package arc
16
 */
17
class lambda
18
{
19
    /**
20
     * Creates a new Prototype object
21
     * @param $properties
22
     * @return lambda\Prototype
23
     */
24 5
    public static function prototype($properties)
25
    {
26
        // do not ever use a single prototype for every other lambda\Prototype
27
        // it will allow evil stuff with state shared across everything
28 5
        return new lambda\Prototype( $properties );
29
    }
30
31
    /**
32
     * Returns a function with the given arguments already entered or partially applied.
33
     * @param callable $callable The function to curry
34
     * @param array $partialArgs unlimited Optional arguments to curry the function with
35
     * @param array $defaultArgs optional default values
36
     * @return callable
37
     */
38 2
    public static function partial(callable $callable, $partialArgs, $defaultArgs = [])
39
    {
40
        return function () use ($callable, $partialArgs, $defaultArgs) {
41 2
            return call_user_func_array( $callable, self::partialMerge( $partialArgs, func_get_args(), $defaultArgs ) );
42 2
        };
43
    }
44
45 2
    private static function partialMerge($partialArgs, $addedArgs, $defaultArgs = [])
46
    {
47 2
        end( $partialArgs );
48 2
        $l = key( $partialArgs );
49 2
        for ($i = 0; $i <= $l; $i++) {
50 2
            if (!array_key_exists($i, $partialArgs) && count($addedArgs)) {
51 2
                $partialArgs[ $i ] = array_shift( $addedArgs );
52 2
            }
53 2
        }
54 2
        if (count($addedArgs)) { // there are $addedArgs left, so there should be no 'holes' in $partialArgs
55
            $partialArgs =array_merge( $partialArgs, $addedArgs );
56
        }
57
        // fill any 'holes' in $partialArgs with entries from $defaultArgs
58 2
        $result =  array_replace( $defaultArgs, $partialArgs );
59 2
        ksort($result);
60
61 2
        return $result;
62
    }
63
64
    /**
65
     * Returns a function with named arguments. The peppered function accepts one argument - a named array of values
66
     * @param callable $callable The function or method to pepper
67
     * @param array $namedArgs Optional. The named arguments to pepper the function with, the order must be the order
68
     *        in which the unpeppered function expects them. If not set, pepper will use Reflection to get them.
69
     *        Format is [ 'argumentName' => 'defaultValue' ]
70
     * @return callable
71
     */
72 1
    public static function pepper(callable $callable, $namedArgs=null)
73
    {
74 1
        if ( !is_array( $namedArgs ) ) {
75
            $ref = !is_array($callable) ? new \ReflectionFunction($callable) : new \ReflectionMethod($callable[0], $callable[1]);
76
            $namedArgs = [];
77
            foreach ($ref->getParameters() as $parameter) {
78
                $namedArgs[ $parameter->getName() ] = $parameter->getDefaultValue();
79
            }
80
        }
81
82
        return function ($otherArgs) use ($callable, $namedArgs) {
83 1
            $args = array_values( array_merge( $namedArgs, $otherArgs ) );
84 1
            return call_user_func_array( $callable, $args );
85 1
        };
86
    }
87
88
    /**
89
    * Returns a method that will generate and call the given function only once and return its result for every call.
90
    * The first call generates the result. Each subsequent call simply returns that same result. This allows you
91
    * to create in-context singletons for any kind of object.
92
    * <code>
93
    *   $proto = \arc\lambda::prototype([
94
    *     'getSingleton' => \arc\lambda::singleton( function () {
95
    *       return new ComplexObject();
96
    *     })
97
    *   ]);
98
    * </code>
99
    * @param callable $f The function to generate the singleton.
100
    * @return mixed The singleton.
101
    */
102
    public static function singleton($f)
103
    {
104 1
        return function () use ($f) {
105 1
            static $result;
106 1
            if (null === $result) {
107 1
                $result = $f();
108 1
            }
109
110 1
            return $result;
111 1
        };
112
    }
113
}
114