8

The code:

public function couts_complets($chantier,$ponderation=100){

    function ponderation($n)
    {
        return($n*$ponderation/100); //this is line 86
    }

            ...

    }

What I'm trying to do: to declare a function B inside a function A in order to use it as a parameter in
array_map().

My problem: I get an error:

Undefined variable: ponderation [APP\Model\Application.php, line 86]

j0k
  • 22,600
  • 28
  • 79
  • 90
L. Sanna
  • 6,482
  • 7
  • 33
  • 47
  • You cannot declare a function inside a function in PHP. – Tomalak Aug 07 '12 at 08:27
  • This construction is not possible in PHP. Move the `ponderation` function outside of the `couts_complets` function and just call it with your parameter. Also possible duplicate of http://stackoverflow.com/questions/1631535/php-function-inside-function – Gerald Versluis Aug 07 '12 at 08:28
  • The docs seems to say otherwise: http://www.php.net/manual/en/functions.user-defined.php – L. Sanna Aug 07 '12 at 08:28
  • You can define a function in a function. see: http://codepad.viper-7.com/oc8EBn – Nanne Aug 07 '12 at 08:29
  • @Nanne No, you can't. PHP will inexplicably find such a construct syntactically valid, but it will not work. You will get a "function redifined" error when you call the "outer" function a second time. http://codepad.viper-7.com/qMR38y – Tomalak Aug 07 '12 at 08:30
  • @Tomalak it will "work", the function is simply declared globally. – salathe Aug 07 '12 at 08:31
  • So how come it not only is valid, but it also works? Did you click the link? – Nanne Aug 07 '12 at 08:31
  • @salathe : yep, and that's annoying to say the least, so you could say it doesn't work on that account, but that would be stretching the term "work" a bit. It does work, but has its drawbacks – Nanne Aug 07 '12 at 08:33
  • @Nanne Did *you* click the link in my comment? – Tomalak Aug 07 '12 at 08:39
  • I did. And yes, you have found the limitation there because of the global thing. That proves indeed that what @salathe says is true, but that's a whole different thing from what you said, as I tried to explain in the 2nd comment. But this doesn't really go anywhere usefull, you have shown a problem indeed, and while I wouldn't call that "it doens't work", it seems you would. Lets leave it a that. – Nanne Aug 07 '12 at 08:43
  • @Nanne This isn't something that's a matter of opinion or open for debate. PHP allows you to create a construct that runs the first time but not when you call it again. That's broken by the very definition of the word. PHP should not even allow this at all. Don't put it as "a language feature that one just has to know how to use". For all intents and puposes: PHP does not support nested function definitions, and the above only works by accident, not by design. – Tomalak Aug 07 '12 at 09:21
  • @tomalak: I'm not sure how to react to that. I can't say I disagree that it was not by design, as shown by the fact that it is used **in an example on php.net** (http://www.php.net/manual/en/functions.user-defined.php , example 3) , because it is not something you allow me an opinion about. I could say that although you might hate PHP for it, it still seems valid and by design, but I am not allowed to disagree with you about this. Still, I'm curious how something that the manual uses as an example is not "by design". It's a stupid feature, but a feature nontheless. – Nanne Aug 07 '12 at 11:17
  • @Nanne You are allowed to disagree with me. The argument that something PHP does is inherently *good* or even *desirable*, just because it is in the docs, is, however, flawed. Of course it is in the docs, and still it is so broken that it does not even deserve the designation "feature". This is one of the reasons why PHP is such a pitiful language. The docs mention it, but blissfully fail to mention what it's good for or that you create a fatal run-time error waiting to happen when you do this. There is no justification this even exists, and it should definitely not be "used". – Tomalak Aug 07 '12 at 11:45
  • @tomalak : You dislike the language, you dislike the documents, you dislike a lot and not without reason. But that does not entitle you to call it "not by design". You say it is not a language feature that you have to know how to use, but it is exactly that. And you can dislike it all you want, but that doesn't make it any different. You can discourage it, sure! you can discourage the use of the language. But you shouldn't twist the facts to suit your opinions. – Nanne Aug 07 '12 at 12:02
  • @Nanne Not everything that happens to work is automatically a language featue. And this, in particular, is nothing that was deliberately implemented. It is an emerging effect of the PHP interpreter hoisting every function into the global space, regardless of where it has been defined in the source. It is by pure coincidence that it does not break right-away. – Tomalak Aug 07 '12 at 12:22
  • 1
    @Tomalak the very fact that this "broken" behaviour has been observed, recorded[*](http://svn.php.net/viewvc/archived/php3/trunk/doc/chapters/lang-syntax.sgml?pathrev=9203&view=markup#l2229) and remained unchanged since very early in PHP's life weighs heavily against your point-of-view that this feature is merely a happy accident. We're not **that** focused on backwards compatibility. – salathe Aug 07 '12 at 12:57
  • @salathe Who is "we"? Anyway. I see little point in defending this "feature", but it's pretty obvious that we won't find common ground here. If you can put it to sensible use, so be it. – Tomalak Aug 07 '12 at 13:08
  • @Tomalak "we" is "the PHP core developers and contributors". – salathe Aug 07 '12 at 13:34
  • No pronlem of declaring a function inside another function , But it is prone to errors …You have to call the outer function before the inner one , Also calling the inner function twice will give you fatal error . – mercury Mar 12 '16 at 19:58

4 Answers4

12

Try this:

public function couts_complets($chantier,$ponderation=100){

    $ponderationfunc = function($n) use ($ponderation)
    {
        return($n*$ponderation/100);
    }

        ...
    $ponderationfunc(123);
}
chiborg
  • 26,978
  • 14
  • 97
  • 115
2

As of php 5.3 you can use anonymous functions. Your code would look like this (untested code warning):

public function couts_complets($chantier,$ponderation=100) {
    array_map($chantier, function ($n) use ($ponderation) {
        return($n*$ponderation/100); //this is line 86
    }
}
Maerlyn
  • 33,687
  • 18
  • 94
  • 85
2

In your current code, $ponderation is not covered by the scope of the function, hence the "undefined" error.

To pass a variable to an "internal" function, use the use statement.

function ponderation($n) use($ponderation) {
FThompson
  • 28,352
  • 13
  • 60
  • 93
  • Hmm, possibly. I'd say that the method should be rewritten as a anonymous function in this situation regardless. – FThompson Aug 07 '12 at 08:35
  • It's only mentioned on the anonymous function's doc page, nowhere in page of the regular user-defined functions. – Maerlyn Aug 07 '12 at 08:40
1

Using a callback function:

In order to use a function as a parameter in PHP it is enough to pass the function's name as a string as such:

array_map('my_function_name', $my_array);

If the function is actually a static method in a class you can pass it as a parameter as such:

array_map(array('my_class_name', 'my_method_name'), $my_array);

If the function is actually a non-static method in a class you can pass it as a parameter as such:

array_map(array($my_object, 'my_method_name'), $my_array);

Declaring a callback function:

If you declare in the global space all is good and clear in the world - for everybody.

If you declare it inside another function it will be global but it won't be defined until the parent function runs for the first time and it will trigger an error Cannot redefine function my_callback_function if you run the parent function again.

If you declare it as a lambda function / anonymous function you will need to specify which of the upper level scope variables it is allowed to see/use.

Calling a callback:

function my_api_function($callback_function) {
    // PHP 5.4:
    $callback_function($parameter1, $parameter2);

    // PHP < 5.3:
    if(is_string($callback_function)) {
        $callback_function($parameter1, $parameter2);
    }
    if(is_array($callback_function)) {
        call_user_func_array($callback_function, array($parameter1, $parameter2));
    }
}
Mihai Stancu
  • 15,848
  • 2
  • 33
  • 51