Skip to content

object-bound closures for initalization, modification of objects #17936

Open
@procodix

Description

@procodix

Description

Objects (and nested ones) are often constructed with local variables:

$o = new Element();
$o->property1 = 'some string';
$o->property2 = new OtherObject();
$o->property2->property = 'some other string';

This can also be achieved by constructor parameters:

$o = new Object('some string', new OtherObject('some other string'));

Can this be done more elegantly?

Problem arises, when we have objects with too many properties. Of course we can use leverage properties and named arguments, but the constructors declarations become lengthy. Even more since we can also define property hooks within the promoted properties. But things get even more complicated, with inheritance and constructing objects with a mixture of ordered params, named params and even variadic params to be passed - for example - into the parent constructor.

Example is the creation of HTML DSL:

new Element(content:"test", classes:"something", elements:[
    new Input(name:"whatever", value:"somevalue", classes:"someclasses", disabled:true),
    //...
];

This gives me some problems.

  1. Introducing a new property: it requires a lot of constructor changes if one avoids variadic arguments passing - which conflicts with ordered parameters often.
  2. boilerplate code inside constructor executes for every property, even if it is not needed (yet)
  3. properties cannot be modified on-the-fly, just assigned.

Closures can solve this, but they are bulky, especially the non-shorthand version:

class Element {
    public function modify(Closure $fnc):static {$fnc($this); return $this;}
}

new Element()->modify(function(Element $e) {
    $e->classes += ' some more classes';
    $e->elements->replace('id3', new Input()->modify(function(Input $i) {
        $i->value = 'new content';
        $i->readonly = false;
    }));
});

Can we have a smoother syntax for this:

new Element({
    $this->classes += ' some more classes';
    $this->elements->replace('id3', new Input({
        $this->value = 'new content';
        $this->readonly = false;
    });
};

Maybe an operator would make sense to execute a block on an object's context:

new Element() <- {...}
new Element(<- {...})
$e <- {
   ...
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions