2
\$\begingroup\$

I made a closure-based PHP structure that behaves mostly like a classical object. To change the object's state, one must derive a new copy by passing the altered state to the newCounter() 'constructor'-function. If you alter $state inside a method without returning newCounter($state), the original object won't be affected because the 'method' closures have only a copy of $state.

function newCounter($state = NULL) {
    if(NULL === $state) {
        $state = [
            'counter' => 0,
            'name' => 'default_name'
        ];
    }
    /* private methods --> */
    $_round = function($number) {
        return round($number, 1);  
    };
    /* public methods --> */
    $add = function($number) use ($state, $_round) {
        $state['counter'] += $_round($number); 
        return newCounter($state);
    };
    $set_property = function($property_name, $value) use ($state) {
        $state[$property_name] = $value;
        return newCounter($state);
    };
    $get_property = function($property_name) use ($state) {
        return $state[$property_name];
    };
    /* expose the public api --> */     
    return function($method, ...$args) use ($state, $add, $set_property, $get_property) {
        return ${$method}(...$args);
    };       
}

The 'instance' then has something like a fluent interface:

$counter = newCounter()('add', 4)('add', 2.999)('set_property', 'name', 'MyCounter');
echo $counter('get_property', 'counter'); // --> 7 
echo $counter('get_property', 'name'); // --> MyCounter

Nested structures are possible, too:

$nested_counter = $counter(
    'set_property', 
    'sub', 
    newCounter()('set_property', 'name', 'SubCounter')
); 
echo $nested_counter('get_property', 'sub')('get_property', 'name'); // --> SubCounter

To change a nested component's state, one must use a workaround:

$nested_with_boo = $nested_counter(
    'set_property', 
    'sub', 
    $nested_counter('get_property', 'sub')(
        'set_property', 
        'name', 
        'Boo'
    )
); 
echo $nested_with_boo('get_property', 'sub')('get_property', 'name'); // --> Boo

Does this structure qualify for an immutable object, and what do you think in general? Have you any Idea how I can enhance $set_property so I don't need this verbose workaround for changing a nested component?

| improve this question | | | | |
\$\endgroup\$
  • \$\begingroup\$ What Is the advantage over using regular classes? To me this just looks like error prone obfuscation. \$\endgroup\$ – slepic Dec 18 '19 at 6:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.