Nested Functions in PHP

By Deane Barker on July 5, 2005

PHP: Advanced Functions: I stumbled in this phenomenon today by accident. I was going nuts trying to find a bug until I realized I had declared a function inside another function. I couldn’t figure out why the parser didn’t fail…when I realized that what I did is completely legal.

When you define a function within another function it does not exist until the parent function is executed. Once the parent function has been executed, the nested function is defined and as with any function, accessible from anywhere within the current document. If you have nested functions in your code, you can only execute the outer function once. Repeated calls will try to redeclare the inner functions, which will generate an error.

Can someone please explain why you’d need this? I know there has to be a reason, but I can’t for the life me figure out what it is.

If the inner function stayed local, that would be one thing. But it becomes global the second you call the outer function, so why not just make it global from the beginning? Is it to save memory by not declaring a bunch of functions until you need them? Has anyone ever done this?

Gadgetopia

Comments

  1. This type of thing would be handy for writing WordPress plugins, actually. The trick is to create a single deployment file. Sometimes the file must be executed stand-alone in addition to being included from the WordPress core during plugin initialization.

    Using nested functions, you could be sure that your required functions are initialized only once, and still use only one file. Usually, I would use is_callable() to determine if a function is available before redeclaring it, but using a nested funciton with a static variable could work, too.

  2. Just stumbled across this post.

    Anyway, to check whether the function exists… use “if (function_exists (‘somefunc’))”!

  3. it’s a must to let a function call itself,, when you use so-called “trees” (in php or in whatever other program)

  4. I needed to write a function which would loop through a multidimensional array and the easiest way was to put a foreach loop inside a function and have it call itself. All of this was inside a top-level function, so it was easiest to do with a nested function.

  5. It seems that one advantage is that you could declare the same function in different contexts.

    Consider a dynamic function call: $functionname=”functionone”;

    Now if you want, you can call: $functioname(); myecho();

    let us say you have defined

    function functionone(){
    ..function myecho(){
    ….echo “I am one”;
    ..}
    }

    function functiontwo(){
    ..function myecho(){
    ….echo “I am two”;
    ..}
    }`

    Now you can call myecho(), and you’ll get “i am one”. Change the original $functionname to “functiontwo” and the same myecho() call will now spit out “I am two”.

  6. because the declaration of the child function is inside the parent, so calling the parent twice is like declaring the child twice…

  7. Coming from JavaScript, I was rather amazed to know the inner function is not local to the parent one. In fact, the way PHP provides execution content still looks unintuitive and inconsistent to me.

    These days, I found a discussion several folks where arguing about nested classes being dropped in PHP5 (http://bytes.com/forum/thread10138.html). Also coming from Java, I felt this is a big lost, but, strangely, no one of the PHP folks around there even accepted that such thinks as name-space polluting or execution context have a reason for being…

    Looks like PHP philosophy is entirely different or something (and, hey, PHP isn’t an Object Oriented Language, no matter what they say).

  8. read ‘the way PHP provides execution content’ as ‘the way PHP provides execution context’ sorry :D

  9. While I understand how this functionality could be used, but the alternate functionality found in other languages seems to be much more useful. From a language structure point of view, this functionality seems cumbersome. Sometimes the best way to prevent people from using a feature wrong is just to remove the feature.

  10. Yes this is a completely usable feature. But I don’t advise using it. There are better ways using object oriented techniques that require an object to be instantiated or created first.

    For instance I have a function to create a table it accepts fld names as parameters in the order they are to appear. At the point of table creation I haven’t supplied or ran an sql statement to fill the table. Prior to filling the table I must have created it, so when I run the create method or what I like to call the constructor I can nest methods
    dependent upon the object actualy have been created within the create function/method. The table is an object that contains the methods to fill it. I thought about suppling the table a resultset or other form of data in the paramters of the table function fillTbl() that it uses to automaticaly format the data for that table. Prior to commiting the DB request I have to know what order table is expecting the data in, as the result set must be in the order specified by the table. I have now come to the conclusion to attach said table to the data/database it needs to do it internaly. In my case I am using strictly my_sql. OK table gets the data definition or the field names in the order they should appear, then what else, it needs to create a result set to manipulate. Seeing table extends the database adapter it has full access to create its own resultset. Being the fields you want in the table are already described we must specify where table should get the data from. I suggest using a number skeme 1= left inner, 2= right inner, 3= left outer, 4= right outer, 5= full inner, 6= full outer. So the parameters for fill table would be outlined as follows. fillTbl($tbl1,”join type ie.123456,$tbl2,”join type”,$tbl3) This function will check arg length and make sure it is not equal to 1 or divisible by 2. Conventions used in database require prepending all fields within a table with the table abbreviation, no two tables can have the same abbreviation. Now you don’t have to specify the table with field in your query. This avoids naming conflict and makes your life easier as you will always know what table a field belongs to. Fill table also checks to see if there are any data restrictions listed. Adding a data restriction is easy within function addRestriction. addRestriction has the following possible restriction types. BETWEEN, LIKE, ISNULL, ORDERBY, OMIT…. The addRestriction function is underdevelopment and will be a grand tool for the creation of future data drivers, however the add restriction function in the first version will just except a string in sql format starting with the where clause as the rest of the request has already been built.

    In Java there is a way to require that an object be instantiated before it is used. You can also declare it in a way that allows you to directly use methods within the class without instantiating it you do this by declaring the method as static and not using instance variables within the method.

    So in php you can create a function that you use like a constructor that contains the methods that can be used nested within it. The class variable without the use of __construct(); from my readings will treat class variables like they or private or protected.

    So overall: I will use object oriented techniques, and I have little use for this feature.

    However if I have a method name processRequest and another named commitRequest I can assure processRequest is called first to validate the request before it is commited by nesting commitRequest within processRequest, the other way of doing this is to make validate and commit private functions and processRequest public where processRequest calls validate and commit in the order they should be process. But as a coder I know how easy it is not to call your methods in order and introduce an error. By nesting you assure that the error never accesses a storage system or somthing and causing more harm. Nesting is a way to restrain yourself from making mistakes. Recieving an error stating that a function isn’t declared is better than updating the last record in que for process with the data for the next record. It’s simple and much like declaring your variable before you use them.

    So on the other hand yes I will use this to save myself troubles in the future.

  11. I know right… create_function is very interesting and so is naming variables by the value of another variable and being able to change the variable names dynamically, this is one reason I like php but it can be done in java and c# with hash tables..

    Not going into detail on how to do this here.. But it is in my notes and you might be able to find it here under my name somewhere.. http://www.110mb.com/forum/how-do-i-synchronize-between-a-local-and-remote-wordpress-site-t39805.0.html

    Read the last page linked good script links I want to remember then just search 110mb for the create_function info…. WOW, today I have in a sense traveled back in time, Man I used to be smart

  12. Hello,

    I found your blog when I was googling for PHP’s nested functions semantics. Having come from a Lisp, Python, and C background, it seemed natural to me to assume that nested functions existed unless someone told me otherwise. But in debugging a rather strange error, your statement helped quite a bit. PHPs function semantics are very strange!

    However, I still find them somewhat useful. They can provide some sort of context for the readers of the code, even if they do not provide that context to PHP. For example, say I have form validation. I’m only going to call validateForm() once, but it will need to validate each piece of form data. Normally, validateForme() would be written like this (yes, I know this is a very simple way to do this and real code is much more robust.)

    function validateForm() { $res = true; if( $GET[‘uname’] !== “” && strlen($GET[‘uname’] > 4 && strlen($_GET[‘uname’] < 8) { //valid username } else { $res = false; } // ... and lots of other ifs, possibly nested, below. }

    This is cumbersome for large validations, so normally you would define separate functions to validate each field:

    function validate_username ( $u ) { if ( strlen($u) < = 8 && strlen($u) >= 4 ) { return true; } return false; }

    //… and more functions

    //Main validation function validateform() { if( validateusername($GET[‘uname’]) && validatepassword($_GET[‘password’]) && //and other validations ) { //Form success } else { //Form failure. }

    … Now, since validate*() are only useful within validateform(), it’s worth simply moving them inside it, to clarify where they are used.

    But I completely agree — this is a mess of a way to do nested functions, and since this is the most useful thing I can think to do with it, shame on PHP!

  13. public function renderFormular(){ // local function to trim indented content function trimMe(&$string){ while($string{0} == ” “) $string = trim($string); return $string; }

        $strFormular = file_get_contents("TemplateToPdf-editFormular.html");
        foreach( $this->arrDataToFill as $strKey => $strValue){
            #$strValue = trim($strValue);
            $strValue = explode( chr(10), $strValue);
    

    // WE NEED IT HERE

            array_walk($strValue, 'trimMe');
    

    // $strValue = implode( chr(10), $strValue);
    $strFormular = str_ireplace(‘###’.$strKey.’###’, $strValue, $strFormular); } return $strFormular; }

  14. “Can someone please explain why you’d need this?”

    Easy. Let’s see an example.

    file1.php:

    file2.php:

    For PHP, I think it is approximatively equivalent to:

  15. by nobody, April 21, 2012 8:25 PM

    “Can someone please explain why you’d need this?”

    Easy. Let’s see an example.

    file1.php: function myLoader() { include(‘file2.php’); }

    file2.php: function myFunction() { /Do something./ }

    For PHP, I think it is approximatively equivalent to: function myLoader() { function myFunction() { /Do something./ } }

  16. I realize this is an old thread, but I developed a plugin system where each plugin is called once to run the plugin, the the plugin id “dropped’ if you will. The nested functions of PHP actually came in handy to keep from polluting the global landscape by not make plugin-specific functions appear everywhere until the plugin is activated. the plugin uses them, then is dumped. the plugin is called only once per session, so it saves some verbose plugins from using too much global namespace needlessly.

Comments are closed. If you have something you really want to say, email editors@gadgetopia.com and we‘ll get it added for you.