Skip to content

Passing named parameters to init() #12

@amulet1

Description

@amulet1

See #11.

The original version of init (and onSubmit) used named parameters, for example in Horde_Form_Type_longtext:

function init($rows = 8, $cols = 80, $helper = array())

The call_user_func_array() in Horde_From::getType() was automatically passing associative arrays to corresponding init function parameters and things were working pretty well.

However, using of named parameters in init is no longer possible due to strict signature checks in PHP 8 and the fact that init function is defined in the parent class (Horde_Form_Type) as

public function init(...$params) {}

We now (after commit 3ecdde1) have issues because sometimes we get numeric indexes in $params - when init is called directly, for example:

$this->_mdy->init($start_year, $end_year, $picker, $format_in, $format_out);

But we could also get named parameters in $params, e.g. in indirect call by Horde_Form's getType:

call_user_func_array([$type_ob, 'init'], $params);

In many cases these issues were individually fixed by handling both named and numeric keys in $params, but I believe they have to be fixed at a higher level once and for all.

Possible solution:
(A) Redesign all places where init is called to always use numeric indexes.

For example, let's look at Horde_Form_Type_longtext's implementation of init:

Original:

function init($rows = 8, $cols = 80, $helper = array())
    {
        if (!is_array($helper)) {
            $helper = array($helper);
        }

        $this->_rows = $rows;
        $this->_cols = $cols;
        $this->_helper = $helper;
    }

Current:

public function init(...$params)
{
    $rows = $params[0] ?? 8;
     $cols = $params[1] ?? 80;
    $helper = $params[2] ?? [];
     if (!is_array($helper)) {
        $helper = [$helper];
    }
    $this->_rows = $rows;
    $this->_cols = $cols;
    $this->_helper = $helper;
}

So, we would need to have a list of expected parameters and their defaults, for example:

[
   'rows' => 8,
   'cols' => 80,
   'helper' => [ ]
]

Note, potentially the existing about() function (with added default values) could/should be used for that.

Then we process $params in the Horde_Form_Type's init using the list:

  • if there is rows key, remove it and set $params[0] to its value
  • if there is no $params[0], set it to the default value 8
  • if there is cols key, remove it and set $[params[1] to its value
  • if there is no $params[1], set it to the default value 80
    ... and so on

We then call newinit with the processed $params (and it can be simplified as all parameters are now guaranteed to exist):

public function newinit(...$params)
{
    $helper = $params[2];
     if (!is_array($helper)) {
        $helper = [$helper];
    }
    $this->_rows = $params[0];
    $this->_cols = $params[1];
    $this->_helper = $helper;
}

(B) Drop init function from the Horde_Form_Type and restore original init functions with named parameters.

Then we would need to make sure only named keys exist in $params when doing the indirect call to init by Horde_Form's getType.

With this approach the existence of 'init` method in a child class is no longer guaranteed and will have to be tested before calling it.


We need to discuss cons and pros this before implementing any changes.

I am also still thinking of a better solution(s) and will update this text accordingly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions