# Inconsistencies in callable, call_user_func and direct variable calls

- Thread: https://externals.io/message/80899
- Original archive: https://news-web.php.net/php.internals/80899
- Started by Marc Bennewitz on 2015-01-20T20:54:10+00:00
- Messages: 31
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/80899.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #80899 — Marc Bennewitz — 2015-01-20T20:54:10+00:00

URL: https://externals.io/message/80899#80899

valid for call_user_func[_array] and callable type-hint but invalid for 
for direct variable calls:
- string "MyClass::staticFunc"
- string "self::staticFunc"
- string "static::staticFunc"
- string "parent::func"
- string "parent::staticFunc"

see http://3v4l.org/1oSO3

Thoughts ?

---

## #80900 — Andrea Faulds — 2015-01-20T20:57:33+00:00

URL: https://externals.io/message/80899#80900 · In reply to: #80899

Hey Marc,

> 
> 
> valid for call_user_func[_array] and callable type-hint but invalid for for direct variable calls:
> - string "MyClass::staticFunc"
> - string "self::staticFunc"
> - string "static::staticFunc"
> - string "parent::func"
> - string "parent::staticFunc"
> 
> see http://3v4l.org/1oSO3
> 
> Thoughts ?

I think it’d make sense if it was supported for normal variable function calls. It’s the most intuitive behaviour.

Thanks.
--
Andrea Faulds
http://ajf.me/

---

## #80901 — Adam Harvey — 2015-01-20T20:59:48+00:00

URL: https://externals.io/message/80899#80901 · In reply to: #80899

> valid for call_user_func[_array] and callable type-hint but invalid for for
> direct variable calls:
> - string "MyClass::staticFunc"
> - string "self::staticFunc"
> - string "static::staticFunc"
> - string "parent::func"
> - string "parent::staticFunc"
>
> see http://3v4l.org/1oSO3
>
> Thoughts ?

This is https://bugs.php.net/bug.php?id=68475 — Julien and I both have
PoC branches implementing this, and agree that it should be fixed in
PHP 7, although I think we differ on whether an RFC is required or
not.

Adam

---

## #80902 — Andrea Faulds — 2015-01-20T21:06:26+00:00

URL: https://externals.io/message/80899#80902 · In reply to: #80901

Hey Adam,

> 
> 
> 
> > […]
> 
> This is https://bugs.php.net/bug.php?id=68475 — Julien and I both have
> PoC branches implementing this, and agree that it should be fixed in
> PHP 7, although I think we differ on whether an RFC is required or
> not.

It’s technically a 'language change’ and would affect the language specification. That said, it seems rather “no-brainer”.

--
Andrea Faulds
http://ajf.me/

---

## #80903 — Levi Morrison — 2015-01-20T21:20:56+00:00

URL: https://externals.io/message/80899#80903 · In reply to: #80901

> 
> > […]
>
> This is https://bugs.php.net/bug.php?id=68475 — Julien and I both have
> PoC branches implementing this, and agree that it should be fixed in
> PHP 7, although I think we differ on whether an RFC is required or
> not.

If `is_callable($f)` returns `true` then it's a bug if you can't call
it with `$f(...$args)`. That's my opinion anyway. I was actually made
aware of this bug some time ago but whenever I intended to fix it I
couldn't remember which case was the issue.

---

## #80906 — Nikita Popov — 2015-01-20T21:46:18+00:00

URL: https://externals.io/message/80899#80906 · In reply to: #80899

> valid for call_user_func[_array] and callable type-hint but invalid for
> for direct variable calls:
> - string "MyClass::staticFunc"
> - string "self::staticFunc"
> - string "static::staticFunc"
> - string "parent::func"
> - string "parent::staticFunc"
>
> see http://3v4l.org/1oSO3
>
> Thoughts ?
>

I would prefer deprecating this alternative notation instead of adding more
support for it. The [$class, $method] form is the canonical form we support
everywhere and which is consistent with the [$obj, $method] callbacks.
There's no point supporting another alternative notation, especially if it
was effectively unusable for a while now already.

Nikita

---

## #80908 — Marc Bennewitz — 2015-01-20T22:02:31+00:00

URL: https://externals.io/message/80899#80908 · In reply to: #80906

> On Tue, Jan 20, 2015 at 9:54 PM, Marc Bennewitz <dev@mabe.berlin
> <mailto:dev@mabe.berlin>> wrote:
>
>     valid for call_user_func[_array] and callable type-hint but invalid
>     for for direct variable calls:
>     - string "MyClass::staticFunc"
>     - string "self::staticFunc"
>     - string "static::staticFunc"
>     - string "parent::func"
>     - string "parent::staticFunc"
>
>     see http://3v4l.org/1oSO3
>
>     Thoughts ?
>
>
> I would prefer deprecating this alternative notation instead of adding
> more support for it. The [$class, $method] form is the canonical form we
> support everywhere and which is consistent with the [$obj, $method]
> callbacks. There's no point supporting another alternative notation,
> especially if it was effectively unusable for a while now already.

I don't think removing this is an option because of a big BC for no reason.

Additionally the string alternative have some advantages:
  - better usable in configurations
  - return syntax of third argument of is_callable
  - ...


>
> Nikita

Marc

---

## #80991 — Stanislav Malyshev — 2015-01-22T20:46:55+00:00

URL: https://externals.io/message/80899#80991 · In reply to: #80902

Hi!

> It’s technically a 'language change’ and would affect the language
> specification. That said, it seems rather “no-brainer”.

I think it makes a lot of sense to have `call_user_func()` and $a() work
identically. I'm not sure though if it should be done by adding
'foo::bar' to $a() or removing it from `call_user_func()`. Adding means
stuff that wasn't callable before may be callable now which may expose
the code for some issues (though if you allow people to call arbitrary
functions in your code you're probably in trouble anyway, so it may not
be a big deal).

I think it's better to have an RFC which clearly states what is
added/removed and that `call_user_func()`/$a()/is_callable/callable
type/whatever else uses it - are all in sync after it and preferably use
the same code, and have tests for all options supported.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #81034 — Nicolas Grekas — 2015-01-23T08:42:02+00:00

URL: https://externals.io/message/80899#81034 · In reply to: #80991

> I'm not sure though if it should be done by adding
> 'foo::bar' to $a() or removing it from `call_user_func()`.


call_user_func('foo::bar') work since 5.2.2 (see http://3v4l.org/k2SOU).

Is there a serious reason to break code that is perfectly fine since 2007.
Breaking BC needs a serious reason IMHO.

---

## #81045 — Andrea Faulds — 2015-01-23T14:37:39+00:00

URL: https://externals.io/message/80899#81045 · In reply to: #80906

Hey Nikita,

> 
> 
> 
> 
> > […]
> 
> I would prefer deprecating this alternative notation instead of adding more
> support for it. The [$class, $method] form is the canonical form we support
> everywhere and which is consistent with the [$obj, $method] callbacks.
> There's no point supporting another alternative notation, especially if it
> was effectively unusable for a while now already.

By the way, this notation is also used by `constant()` and `defined()`:

$ php -r 'class Foo { const FOO = 3; } var_dump(constant("Foo::FOO"), defined("Foo::FOO"));'
int(3)
bool(true)

It’s also very intuitive compared to the function syntax. I see no reason we shouldn’t support it more widely.

--
Andrea Faulds
http://ajf.me/

---

## #81047 — Rowan Collins — 2015-01-23T17:56:51+00:00

URL: https://externals.io/message/80899#81047 · In reply to: #81045

Andrea Faulds wrote on 23/01/2015 14:37:
> Hey Nikita,
>
> > […]
> By the way, this notation is also used by `constant()` and `defined()`:
>
> $ php -r 'class Foo { const FOO = 3; } var_dump(constant("Foo::FOO"), defined("Foo::FOO"));'
> int(3)
> bool(true)
>
> It’s also very intuitive compared to the function syntax. I see no reason we shouldn’t support it more widely.

+1 on this being more intuitive syntax, although the array syntax is 
convenient for dynamically selecting each part separately, and obviously 
for calling non-static methods.

It actually feels kind of weird that as of PHP 7, an array is more 
callable than a string:

class Foo { static function bar() { echo 'Hello'; } }

Foo::bar(); // OK
['Foo', 'bar'](); // OK
'Foo::bar'(); // FATAL ERROR

http://3v4l.org/f7rvc

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #81061 — Stanislav Malyshev — 2015-01-24T00:15:01+00:00

URL: https://externals.io/message/80899#81061 · In reply to: #81047

Hi!

> Foo::bar(); // OK
> ['Foo', 'bar'](); // OK
> 'Foo::bar'(); // FATAL ERROR

I'm not sure why one would ever need/want the latter. IMO, it just looks
weird.

-- 
Stas Malyshev
smalyshev@gmail.com

---

## #81074 — Rowan Collins — 2015-01-24T14:24:56+00:00

URL: https://externals.io/message/80899#81074 · In reply to: #81061

>Hi!
>
> > […]
>
>I'm not sure why one would ever need/want the latter. IMO, it just
>looks
>weird.

Well, they both look weird as literals like that, but the array looks the wierder of the two to me. Representing a static call in some external configuration is an example where a single string in normal PHP syntax would make more sense than needing to create a 2-element array.

---

## #84814 — Nicolas Grekas — 2015-03-15T10:15:53+00:00

URL: https://externals.io/message/80899#84814 · In reply to: #81074

> > […]
>

Hi,

does this topic need to be addressed before PHP7 goes feature freeze? Or is
it a bugfix? (Julien already provided a patch)
I'm not familiar with writing RFCs. I fear I won't be able to handle it on
schedule if one is required.
Can someone help please?

Regards,
Nicolas

---

## #85213 — Yasuo Ohgaki — 2015-03-19T11:51:31+00:00

URL: https://externals.io/message/80899#85213 · In reply to: #84814

Hi all,

On Sun, Mar 15, 2015 at 7:15 PM, Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:

> > […]
>
> Hi,
>
> does this topic need to be addressed before PHP7 goes feature freeze? Or is
> it a bugfix? (Julien already provided a patch)
> I'm not familiar with writing RFCs. I fear I won't be able to handle it on
> schedule if one is required.
> Can someone help please?


It's nice if this bug could be fixed by PHP7.

Distinguishing array and callable is problematic.
Array callable is better to be deprecated in the long run. IMHO.

Regards,

--
Yasuo Ohgaki
yohgaki@ohgaki.net

---

## #85214 — Sebastian B.-Hagensen — 2015-03-19T12:48:00+00:00

URL: https://externals.io/message/80899#85214 · In reply to: #85213

Hi,

2015-03-19 12:51 GMT+01:00 Yasuo Ohgaki <yohgaki@ohgaki.net>:
> Distinguishing array and callable is problematic.
> Array callable is better to be deprecated in the long run. IMHO.

Then how would you write an callback containing an already constructed object?
$a = [$object, 'method'];

The alternative is unnecessarily cumbersome:
$a = function($methodArg1, $methodArg2) use($object) { return
$object->method($methodArg1, $methodArg2); };

---

## #85217 — S.A.N — 2015-03-19T16:17:50+00:00

URL: https://externals.io/message/80899#85217 · In reply to: #85214

> Then how would you write an callback containing an already constructed object?
> $a = [$object, 'method'];
>
> The alternative is unnecessarily cumbersome:
> $a = function($methodArg1, $methodArg2) use($object) { return
> $object->method($methodArg1, $methodArg2); };

$object->$methodName(...$args);

---

## #85218 — Patrick Schaaf — 2015-03-19T16:25:48+00:00

URL: https://externals.io/message/80899#85218 · In reply to: #85217

On Thursday 19 March 2015 18:17:50 S.A.N wrote:
> > […]
> 
> $object->$methodName(...$args);

That's a call. Requested was an assignment. You cannot assign that and pass it 
around for later calling. You cannot pass that as a callable parameter.

Patrick

---

## #85219 — Sebastian B.-Hagensen — 2015-03-19T16:27:48+00:00

URL: https://externals.io/message/80899#85219 · In reply to: #85217

Hi,
2015-03-19 17:17 GMT+01:00 S.A.N <ua.san.alex@gmail.com>:
> > […]
>
> $object->$methodName(...$args);

You would still need an array to pass the information about the
callback to another context. The syntax you detailed is not usable by
the callable typehint and internal functions requiring a callback. No
improvement made. The better alternative may be to deprecate strings
as callbacks (if one should be deprecated at all) and always require a
closure or or an array with one of the following signatures
array(string); array(string, string); array(object, string)

Another way to unify array and string callback may be to use the
callable syntax and have it return a closure:
callable('strlen');
callable($object, $methodName);
callable('class', 'staticMethod')

---

## #85220 — Rowan Collins — 2015-03-19T17:08:17+00:00

URL: https://externals.io/message/80899#85220 · In reply to: #85219

Sebastian B.-Hagensen wrote on 19/03/2015 16:27:
> Another way to unify array and string callback may be to use the
> callable syntax and have it return a closure:
> callable('strlen');
> callable($object, $methodName);
> callable('class', 'staticMethod')

Andrea proposed a slightly different syntax for function references a 
few months back - see withdrawn RFC [1] and accompanying Internals 
thread [2].

I actually quite like the callable() syntax. Whereas Andrea's suggestion 
was a parser rule that took a bare string, like &foo, this would have to 
always take a string, like callable('foo'), but that's good if we want 
to roll in dynamic callbacks as well:

Right now, we have to embed the type information in the variable name, 
because this is just a string:
$hook_callback = 'hook_' . $hook_name;
This has a much strong information scent:
$hook = callable('hook_' . $hook_name);

There's then the question of what kind of object it would return - a 
Closure? Some child or sibling of Closure? What methods could be 
usefully provided?

What should happen if the arguments provided aren't callable? Throw an 
exception?

Also, do we still need a way to delay testing of callability, to allow this:

class A {
     private function foo() { echo 'foo'; }
     public function bar(callable $call) { $call(); }
}
$a = new A;
// A::foo is not callable here, but will be when we get inside A::bar
var_dump(is_callable([$a, 'foo'] ));
$a->bar( [$a, 'foo'] );

Currently works: http://3v4l.org/pNZgn


[1] https://wiki.php.net/rfc/function_referencing
[2] http://marc.info/?t=140710275400001&r=2&w=2

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #85224 — Levi Morrison — 2015-03-19T17:48:11+00:00

URL: https://externals.io/message/80899#85224 · In reply to: #85220

> There's then the question of what kind of object it would return - a
> Closure? Some child or sibling of Closure? What methods could be usefully
> provided?

Yes, it's a closure. I've actually fleshed this out quite a bit, and
there are a few important questions:

 - With methods do you allow unbound closures? `callable("Foo::method")` ?
 - How do you provide a context object? Two parameters? If so, what
order? The object first makes more sense, but that means you have a
string for your first parameter when there is only one, but an object
if there are two. So you put the context second and it's kind of weird
to do `callable("method", $foo)`

Also note that if we had a unified table for properties, methods and
constatns this is vastly simplified:
  -  $foo::method could provide an unbound, scoped closure
  - $foo->method could provide a bound closure

Or you do alternative grammar rules inside of callable, such that
`callable(foo::method)` must would check for a method instead of a
constant.

All in all, I really wish we had unified properties, methods and
constants. It would also have the advantage that if you have a
property of an object that is a callable you could call it with normal
syntax `$foo->property()` instead of having to do things like `$f =
$foo->property; $f()`.

Callable might work, though.

---

## #85233 — Dennis Birkholz — 2015-03-19T19:05:32+00:00

URL: https://externals.io/message/80899#85233 · In reply to: #85219

Hi,

Am 19.03.2015 um 17:27 schrieb Sebastian B.-Hagensen:
> Another way to unify array and string callback may be to use the
> callable syntax and have it return a closure:
> callable('strlen');
> callable($object, $methodName);
> callable('class', 'staticMethod')

but before that happens, we should make closures serializable.

Greets
Dennis

---

## #85235 — Levi Morrison — 2015-03-19T19:26:39+00:00

URL: https://externals.io/message/80899#85235 · In reply to: #85233

> Hi,
>
> Am 19.03.2015 um 17:27 schrieb Sebastian B.-Hagensen:
> > […]
>
> but before that happens, we should make closures serializable.

What does closures being serializable have to do with this feature?

---

## #85236 — Dennis Birkholz — 2015-03-19T19:44:04+00:00

URL: https://externals.io/message/80899#85236 · In reply to: #85235

Hi,

Am 19.03.2015 um 20:26 schrieb Levi Morrison:
> 
> > […]
> What does closures being serializable have to do with this feature?

If you replace the array($object, 'method') syntax by callable($object,
'method') which returns a closure, you can not serialize callables any
more which is currently possible. Before we replace working language
features by closures we should update closures to be usable in all
required situations.

Greets
Dennis

---

## #85239 — Yasuo Ohgaki — 2015-03-19T20:50:28+00:00

URL: https://externals.io/message/80899#85239 · In reply to: #85214

Hi Sebastian,

On Thu, Mar 19, 2015 at 9:48 PM, Sebastian B.-Hagensen <
sbj.ml.read@gmail.com> wrote:

> 2015-03-19 12:51 GMT+01:00 Yasuo Ohgaki <yohgaki@ohgaki.net>:
> > […]
>
> Then how would you write an callback containing an already constructed
> object?
> $a = [$object, 'method'];
>
> The alternative is unnecessarily cumbersome:
> $a = function($methodArg1, $methodArg2) use($object) { return
> $object->method($methodArg1, $methodArg2); };


I'm not proposing deprecate it soon, but in the long run.
It will need a decade to deprecate it.

Regards,

--
Yasuo Ohgaki
yohgaki@ohgaki.net

---

Next page: https://externals.io/message/80899.md?page=2
