How does scope work for functions in PHP? Can I use function A (defined outside function B) from within function B?
From php manual:
All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa.
So yes, you can.
Yes, you can do it like this:
function A()
{
...
}
function B()
{
A();
}
B();
Variable scope if for variables.
There is no "scope" for functions... except when using namespaces.
Quoting the User-defined functions section of the manual :
All functions and classes in PHP have
the global scope - they can be called
outside a function even if they were
defined inside and vice versa.
Related
I have six functions that require a global variable. In an attempt to reduce redundancy, I wrote a new function that is triggered rather than triggering all six. This one function has a global $var that is required by the other functions.
So, it looks like this
function one_function_for_the_rest() {
global $importantVar;
functionOne();
functionTwo();
functionThree();
}
but the global variable is not being seen by the called functions. Am I doing this incorrectly, or is this a limitation I was not aware of?
You're not doing it correctly as the variable is defined when on_function_for... is called. An easier way for this would be just to have $importantVar; at the start of the code.
Or wrap your functions inside a class and put the variable inside the class.
e: so basically do : function myFunc($important) { stuff } and when calling the function do myFunc($importantVar)
example :
$asd = "lol";
class myclass {
public function lol($asd) {
echo $asd;
}
}
$obj = new myclass;
$obj->lol($asd);
You're not doing it correctly. Each function either needs to use the global scope identifier, like global $importantVar;, or have $importantVar passed as a parameter. Otherwise, the other functions don't have $importantVar in their respective scopes.
Simply calling a function from within one_function_for_the_rest does not tell that other function anything about global variables or variables used in one_function_for_the_rest. In technical terms, your function calls do not bring $importantVar into the respective scopes of functionOne, functionTwo, or functionThree.
PHP does not have the same scoping rules as most other languages have. That is the downside to not having to declare variables with var as in JavaScript or other similar constructs.
Basically in PHP, every function used is only available in that function. There are three exceptions:
The global keyword
The $this variable inside objects. This one is also "magic" as it's also available inside anonymous functions defined inside a class.
When declaring an anonymous functions you can bind variables to it using use.
I have the following simple code:
$a = 'hello';
function myfunc() {
echo 'in myfunc';
}
class myclass {
function __construct() {
myfunc();
echo $a;
}
}
$m1 = new myclass();
The echo $a within the method gives an error as you would expect since $a is in the global scope and cannot be accessed from within the class without first declaring it as global. That is documented in the PHP manual.
The call to myfunc() does work and I don't understand why. It is also declared in the global scope but the method can access it without first declaring it as global. I can't seem to find anything in the PHP manual that explains why this works.
Maybe I've been doing PHP for too long and this is something so simple I've forgotten how it works. Any insight or a link to where in the PHP manual it says you can access a global function from within a class method would be appreciated.
thanks in advance.
Functions aren't scoped (except if you use namespaces). Only methods are in classes and variables everywhere.
It's supposed to work; everything is correct: you can call functions, once defined, from everywhere.
I'm not sure if this is a new thing for namespaces...
http://www.php.net/manual/en/language.namespaces.fallback.php
Blockquote
For functions and constants, PHP will fall back to global functions or constants if a namespaced function or constant does not exist.
class A{
static $var = true;
function f(){
}
}
vs
class A{
function f(){
static $var = true;
}
}
There doesn't seem to be any difference. Are there any advantages of using one over the other?
Note that $var would be used in the f() function only. I understand that declaring it in the class header is required if the variable needs to be used in multiple functions
If you only use the static variable in the f function, there's only a scope difference, that means no difference as long as you don't try to use it elsewhere.
When used in local scope, the static variable value is kept between each function call. See Static variables part of this page.
Thanks insertusernamehere for pointing that out.
In the later example you may only use the var inside the f function. The other is accessible anywhere from inside the class A::var or outside A::var
In Python you can have the following:
def foo(param1, param2):
def bar():
print param1 + param2
bar()
I am having some difficulties with this behaviour in PHP though.
I expect this to work in the following way:
function foo($param1, $param2)
{
function bar()
{
echo $param1 + $param2;
}
bar();
}
But that fails. So I read some about closures (this is called a closure is it not? It is in Python, that I know). And in the php documentation about anonymous functions (which they said to have been implemented as closures) they tell you to use the use() expression in the following manner:
function foo($param1, $param2)
{
function bar() use($param1, $param2)
{
echo $param1 + $param2;
}
bar();
}
But that still fails. So I changed it to the PHP-anonymous function a-like like this:
function foo($param1, $param2)
{
$bar = function() use($param1, $param2)
{
echo $param1 + $param2;
};
$bar();
}
That does work, however it just looks really ugly. Am I missing something? Can I improve this in any way? Or will I just have to use the 'ugly' way?
(I am not looking for a discussion about if closures are useful)
I couldn't find the function bar() use($param1, $param2) syntax on the manual page you linked to, just the "ugly" version that works (which is truly anonymous). I guess you'll have to use that.
On your second example, bar is not a closure. To create a closure in PHP you have to use the ugly use, or the Closure class. Every function will create its own local scope, but closures are not automatic.
PHP seems to have an odd definition for the term "closure", as you probably noted when you read the manual. They define it as a synonym for "anonymous function":
Anonymous functions, also known as closures (...)
Confusing, right? Later, they explain you need the use keyword if you want to inherit the parent scope:
Closures may also inherit variables from the parent scope. Any such variables must be declared in the function header.
The PHP Wiki rfc page on closures gives us some hints on why closures were implemented this way:
PHP's notion of scope is quite different than the notion of scope other languages define. Combine this with variable variables ($$var) and it becomes clear that automatically detecting which variables from the outer scope are referenced inside are closure is impossible. Also, since for example global variables are not visible inside functions either by default, automatically making the parent scope available would break with the current language concept PHP follows.
In PHP, you can't access intermediate scopes. You only have your local scope, and the global scope. This is an artefact of the perverse scope rules of PHP, which are the complete opposite of any sane language's scope rules.
In PHP, a named function declaration (function bar ()) declares a function in the global scope. So in your first example, when you run your foo function, it will define a bar function in the global scope, and then everybody can access the bar function as if you declared it outside of foo. Functions and variables are separate in PHP. There is just one scope for named functions: global; whereas you have local variables, there is no such thing as locally-scoped functions.
In other words, putting it inside of foo is an illusion; named function declaration always declares it globally; putting it inside foo simply delays the time when the declaration is run (thus delaying when it is defined) to the execution of foo.
A closure is what you need. Other answers have showed you how to do that.
I have tested the following and it doesn't work. Is there a similar way of achieving this?
A compiling class which formulates a template:
private function include_header () {
function _metadata () {
// Metadata compiler
return $metadata;
}
include (path . "header.php");
}
header.php
<html>
<head>
<?php
_metadata ();
?>
<title>Hello Stackoverflow!</title>
</head>
<body>
...
The _metadata (); function is only available within the include_header (); function - nowhere else in the class. I don't want to have to write $this->_metadata (); in the template file only _metadata ();. Is that achievable?
Alternatively one could create an external file, for example functions.php which has the underscore functions specifically for the template - but I'd much rather see if the original query is possible.
Thank you in advance.
From the manual:
All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa.
So, essentially, you can't do what you're trying to do. _metadata will always be a global function if it is defined with the function _metadata() { syntax. The normal function syntax only supports global functions.
However, PHP 5.3 introduces something called "anonymous functions". These can be assigned to a variable. Since variables can be scoped to a function scope (they are only global if you explicitly say so), you can limit them in this way.
For instance:
$_metadata = function() {
// Metadata compiler
return $metadata;
};
This could then be called in header.php with:
<?php $_metadata(); ?>
Note that this is less stable: it is, for instance, possible to redefine the variable to be a different anonymous function – or indeed not a function at all. The safest solution, ultimately, is to use a templating language that solves these issues for you. If not, you can either accept that you'll have to use global functions or anonymous functions.
You can't define nested function in PHP. I mean, you can, but there's no purpose since they'll have a global scope and therefore they will be callable from any point of the script.
But you actually don't need to define a _metadata() function, you can just execute all the function logic inside include_header() and then store everything in the variable $metadata, which will be printed in the include with a simple <?php echo $metadata; ?>.
If you really need to define a function you can use the function create_function() or (just for PHP > 5.3) an anonymous function. Since they will be encapsulated inside a variable, which has a function scope, they won't be available outside.