php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #71903 Introduce $offset parameter for get_defined_functions()
Submitted: 2016-03-25 20:04 UTC Modified: 2016-04-02 11:52 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:-1 (-100.0%)
From: andreas at dqxtech dot net Assigned:
Status: Wont fix Package: Scripting Engine problem
PHP Version: 7.0.5RC1 OS: Linux
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2016-03-25 20:04 UTC] andreas at dqxtech dot net
Description:
------------
Some frameworks / CMSes (mostly Drupal, maybe others) rely on function naming patterns for their internal functionality.

Discovery is often implemented with a lot of function_exists($module . '_' . $hook), or even function_exists($module . '_' . $hook . '_' . $suffix) or similar, for a lot of $module + $hook (+ $suffix) combinations. This can be quite costly.

An alternative is to iterate over get_defined_functions()['user'], and analyze each function for the patterns it matches.

A problem with this is that new functions can appear when new files are included. get_defined_functions() is cheap when called once in a request, but calling it repeatedly can be costly (around ~2ms each call, but depends on the project).

The list of returned functions is already ordered by definition time. New functions are towards the end of the list. Hence, it is possible to distinguish newly added functions by keeping track of count(get_defined_functions()['user']), when calling it repeatedly. But the cost still adds up.

I imagine that get_defined_functions() would be faster if it could be called with an $offset parameter, so it would only return the functions from this offset onwards.

The ['internal'] functions do not really change during a request, so I think with this parameter set, we only need ['user'] functions.

Following another request, https://bugs.php.net/bug.php?id=51855, the parameter could be set to 'internal' or 'user' to specify one of the arrays.

Test script:
---------------
function f0() {}
function f1() {}
function f2() {}
function f3() {}

assert(get_defined_functions()['user'] === array('f0', 'f1', 'f2', 'f3'));
assert(get_defined_functions('user') === array('f0', 'f1', 'f2', 'f3'));
assert(get_defined_functions(0) === array('f0', 'f1', 'f2', 'f3'));
assert(get_defined_functions(1) === array('f1', 'f2', 'f3'));
assert(get_defined_functions(3) === array('f3'));
assert(get_defined_functions(4) === array());
assert(get_defined_functions(5) === array());

Expected result:
----------------
All assertions pass. No warnings or errors.

Actual result:
--------------
https://3v4l.org/q68fI

Warning: get_defined_functions() expects exactly 0 parameters, 1 given in /in/q68fI on line 8
Warning: assert(): assert(get_defined_functions('user') === ['f0', 'f1', 'f2', 'f3']) failed in /in/q68fI on line 8
Warning: get_defined_functions() expects exactly 0 parameters, 1 given in /in/q68fI on line 9
Warning: assert(): assert(get_defined_functions(0) === ['f0', 'f1', 'f2', 'f3']) failed in /in/q68fI on line 9
Warning: get_defined_functions() expects exactly 0 parameters, 1 given in /in/q68fI on line 10
Warning: assert(): assert(get_defined_functions(1) === ['f1', 'f2', 'f3']) failed in /in/q68fI on line 10
Warning: get_defined_functions() expects exactly 0 parameters, 1 given in /in/q68fI on line 11
Warning: assert(): assert(get_defined_functions(3) === ['f3']) failed in /in/q68fI on line 11
Warning: get_defined_functions() expects exactly 0 parameters, 1 given in /in/q68fI on line 12
Warning: assert(): assert(get_defined_functions(4) === []) failed in /in/q68fI on line 12
Warning: get_defined_functions() expects exactly 0 parameters, 1 given in /in/q68fI on line 13
Warning: assert(): assert(get_defined_functions(5) === []) failed in /in/q68fI on line 13

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-03-25 20:10 UTC] andreas at dqxtech dot net
One flaw of this proposal is that the return value of get_defined_functions() would change from 'string[]' to 'string[][]|string[]'. Which of course is still 'array' === 'array'.

Stable return types are generally preferable.

A solution could be to have a separate function, e.g. get_user_defined_functions().

I will leave this argument to others.
 [2016-03-25 20:15 UTC] stas@php.net
-Package: PHP Language Specification +Package: Scripting Engine problem
 [2016-03-25 20:15 UTC] stas@php.net
Given how many criteria is there for selection which functions you need, it's simpler to just write your criteria as a function or expression and apply it to array_filter(get_defined_functions()). Unless there's a clearly defined common use case, I don't think this belongs in core.
 [2016-03-25 20:21 UTC] andreas at dqxtech dot net
@stas
The reason to put this in core is to make it affordable to be called repeatedly in a request. The array_filter() does not help, because core still needs to produce the complete list each time, before it is being filtered.
 [2016-04-02 11:52 UTC] krakjoe@php.net
-Status: Open +Status: Wont fix
 [2016-04-02 11:52 UTC] krakjoe@php.net
The order of function names is not reliable:

<?php
function f0() {}
function f1() {}
function f2() {}
function f3() {}

var_dump(get_defined_functions("user"));

krakjoe@fiji:/usr/src/php-src$ sapi/cli/php -n test.php
array(2) {
  ["internal"]=>
  array(0) {
  }
  ["user"]=>
  array(4) {
    [0]=>
    string(2) "f0"
    [1]=>
    string(2) "f1"
    [2]=>
    string(2) "f2"
    [3]=>
    string(2) "f3"
  }
}
krakjoe@fiji:/usr/src/php-src$ sapi/cli/php test.php   
array(2) {
  ["internal"]=>
  array(0) {
  }
  ["user"]=>
  array(4) {
    [0]=>
    string(2) "f3"
    [1]=>
    string(2) "f2"
    [2]=>
    string(2) "f1"
    [3]=>
    string(2) "f0"
  }
}

Opcache, or anything else, is free to change the order of the functions as it pleases.

I'm afraid, this can't be done reliably.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 10:01:29 2024 UTC