0

Setting

Within SomeClass there is f2member taking two integer arguments and producing its sum. The test passes showing that the call actualy works and retrieves the expected result. Which is calling $gwith two parameters 1 and 1 returning 2.

Important: This works only for php 5.4.11 and upwards compatibility check

class SomeClass extends PHPUnit_Framework_TestCase
{   
    function f2member($a,$b)
    {
        return $a + $b;
    }

    /**
     * @test
     */
    public function test()
    {
        $g = array($this,'f2member');
        $this->assertEquals(2, $g(1,1)); // squiggle line under $g
    }
}

Problem

However, this produces a warning inside phpStorm on every method invocation and a squiggle line under $g:

squiggle line warning in phpStorm

Function name must be callable - string, Closure or class implementing __invoke, currently array

The origin of the warning is clear to me and now i am looking for ways to avoid these warnings. A requirement is, that i dont want to change the style of calling the function. Another thing i don't want to do is to deactivate this warning. I would rather prefer to wrap something around it, which provides the necessary information to the type system.

Attempt

I already encountered several solutions to remove the warnings. One is to define a user defined function, which only documents the required target type.

/**
 * @param array $arr
 *
 * @return callable
 */
function callable_for($arr)
{
    return $arr;
}

This returns an array, but also explicitly tells the type system what comes out of the callable_for function. With this type annotation in place phpStorm now stops complaining about this warning, although it still returns an array.

$g = callable_for(array($this,'f2member'));

Question

Isn't there something out of the box like my callable_for in php to achieve this? If the answer is no, then i am looking for the most concise solution we can find.

I already tried looking on SO, php.net and google. Maybe, I just searched for the wrong word combinations, here are just two samples:

  • array to callable php
  • create callable method handle php

BigPicture

Just in case suspects arise this is a X/Y problem: I have another function taking a callable as a parameter. With closures it is very natural to define something, which can be invoked later on. However, how do i define a callable for a member or a static method without wrapping it in another delegation Closure? The array notation allows to be used to uniformly pass: closures or static/member method handles to my later function. I am now trying to find a concise solution to this, which comes close to this.

Community
  • 1
  • 1
isaias-b
  • 2,255
  • 2
  • 25
  • 38

2 Answers2

0

Thus, another advancement could be, to modify callable_for to take two arguments and wrap both responsibilities; to create the array and to document the target return type.

/**
 * @param mixed $context
 * @param string $method
 *
 * @return callable
 */
function callable_for($context, $method)
{
    return array($context, $method);
}

Using this implementation raises the conciseness of $g's declaration to an acceptable level.

$g = callable_for($this,'f2member');

This function still returns an array, but the type system can use the given information to correctly treat this array for dynamic method invocation.

isaias-b
  • 2,255
  • 2
  • 25
  • 38
  • this returns an array, not a callable. – I wrestled a bear once. Jan 05 '16 at 21:41
  • @Pamblam I updated the question to reflect that I know this returns an array, but also added the motivation for this awkward looking setup. – isaias-b Jan 05 '16 at 23:01
  • i deleted my answer, obviously i didn't understand your question, but in reply to your other comment, i would love to see how you can call an array if you would be so kind as to post an example of that.. – I wrestled a bear once. Jan 05 '16 at 23:27
  • @Pamblam Nobody is perfect, just run phpunit on the given phpunit test in the question. The array in this assignment `$g = array($this, 'f2member');` will be turned into something, which can be passed an argument list to, when calling `$g(1,1)` on it, it should evaluate _as expected_. This will then return `2` and let the assertion in the test case pass. Or just hit [this link](https://3v4l.org/as5Qc). However, from the linked answer on the right, i got the information that this style might be discouraged. – isaias-b Jan 05 '16 at 23:45
  • wow, that is super cool thanks for sharing.. i'm sorry for doubting you :p however, if you look at your 3v4l, it shows the same error for php <5.4. looks like the issue is related to the version of PHP you're using. – I wrestled a bear once. Jan 05 '16 at 23:54
  • I already added the information to the question, to reduce confusion. I already was aware of the compatibility break at that version, but you also made me think of this from a new perspective now. Could it be that my php runtime in phpStorm uses an older version for code validation? I couldn't find a config for it on the quick run i will check if this tomorrow. This might be the cause for the warning. Although i should have received an error, but i definitely get a warning, though. – isaias-b Jan 06 '16 at 00:01
0

The question was asked four years ago but after some research I found the Closure::fromCallable method: https://www.php.net/manual/de/closure.fromcallable.php

René Pardon
  • 187
  • 4
  • 12