This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
nested functions in php throws an exception when the outer is called more than once
why does
function foo(){
function bar(){
}
}
bar();
return fatal error on nonexistent function bar
while
function foo(){
function bar(){
}
}
foo();
foo();
gives fatal error on duplicate declaration for bar()?
does php handle the function as global or in the parent's function scope?
The function itself is defined at global scope, even if it was defined inside another function. In the first case, if you don't call foo() before bar(), bar() will not yet exist.
You can test with function_exists() before creating it:
function foo(){
// Don't redefine bar() if it is already defined
if (!function_exists("bar")) {
function bar(){
}
}
}
However, since the nested function is not scoped to the outer function, the use cases for defining a function inside another function are somewhat limited. Furthermore, it introduces some odd side-effects into your code which can become difficult to understand and maintain. Consider if you really want to do this, and rethink your reason for doing so if necessary. You might be better served by namespaces or classes/objects if what you're looking for is scope limits.
Functions are always created in the global scope, but only when their definition is executed.
The function "inside" is only declared when the outer function is called.
In your first example, you don't call foo(), therefore bar() is never declared.
In your second example, you call foo() twice, so bar() is declared twice.
In the first example, bar is declared in the function foo. So calling bar makes no sense without first calling foo since its definition hasn't been executed yet. In the second example, you are calling foo twice so the bar function gets declared twice.
Related
class foo {
public function bar(){
$var = 10;
return $var
}
}
I have this class in one file, can i call this class and function in another file and somehow edit the variable $var, and then store it to the same variable so it can be used after in the class?
You cannot "reach into" functions and change variables used within them. From a sort of theoretical computer science standpoint, it doesn't even make sense. The variable $var only exists while the function is executing. When you call $foo->bar(), the code in it runs, creating the local variable $var, assigning 10 to it, then returning it. Then the whole scope is destroyed and the variable $var ceases to exist. It's not possible to alter it at all from code outside of Foo::bar, because it doesn't exist while code outside of Foo::bar is running. That's no to mention variable scope or encapsulation at all...
Most likely you'll want a property:
class Foo {
public $var = 10;
public function bar(){
return $this->var;
}
}
Public properties are a bad idea in and of themselves in most OO contexts, but that's a different cattle of fish I won't go into here.
I thought usually we use static method because we do not need to instantiate objects. and we can use className::staticFunction to call static method, bub today found:
test1.php
<?php
class Foo {
static public function helloWorld() {
print "Hello world " ;
}
}
Foo::helloWorld();
test2.php
<?php
class Foo {
public function helloWorld() {
print "Hello world " ;
}
}
Foo::helloWorld();
Question:
Both of above scripts work. We did not declare function as static, we can still use className::staticFunction to call the function. Why do we need use static methods?
We did not declare function as static, we can still use className::staticFunction
What you probably didn't notice is that PHP complains about the second type of invocation:
PHP Strict Standards: Non-static method Foo::helloWorld() should not be called statically in php shell code on line 1
Strict Standards: Non-static method Foo::helloWorld() should not be called statically in php shell code on line 1
To make these notices visible you need to set the value of error_reporting to -1, either using ini_set() or via the php.ini configuration file; btw, this is recommended during development.
Conclusion
A function that's called statically should be declared as static function xyz().
Update
Btw, using the scope resolution operator :: doesn't necessarily mean you're making a static call; consider this example:
class Foo
{
public function helloWorld()
{
print "Hello world ";
}
public function doSomething()
{
self::helloWorld();
}
}
$f = new Foo;
$f->doSomething();
This works because using self:: as opposed to Foo:: doesn't change the invocation "mode" (unless the method you're calling is defined as static).
The "problem" with static methods is the way they're called:
Foo::bar();
Any call to a static method is by necessity hardcoded and cannot easily be substituted. Compare with:
$foo->bar();
$foo is a variable here, meaning the exact object and implementation of bar() can be substituted. This is important for and the basis of dependency injection.
You'd use a static method for:
first and foremost cases where you don't need individual object instances
anything you need to do before an object can be instantiated
alternative object constructors, for instance DateTime::createFromFormat() instead of new DateTime
idempotent utility functions which you are 100% sure never need to be substituted or mocked
You may use static functions in other scenarios here and there, but these are the main points. You need to be aware that declaring a method static means you need to call it statically, which means its call-time use cannot really be altered. For a long treaty on this subject, read How Not To Kill Your Testability Using Statics.
Well a simply hello world program might not be able to show a big difference is the usage of static vs not but take a look at this class
class foo {
private $a = 1;
private static $b = 2;
public function foobar()
{
echo $this->a;
}
}
in this above class if you call foobar statically then $this->a will not resolve.
PHP is funny like that, but I'll usually have a utilities class which takes arguments of things to perform logic on and return. Stuff like this doesn't need an instantiated class. It's up to the user/developer to correctly call methods (read: use the correct method accessors).
When you are working on a large OOP based project, you’ll no doubt be working with many classes (both parent and child classes). An unfortunate consequence of this is that in order to access elements from different classes, they must manually be passed through each class (or worse, storing an instance in a global variable). This can be painstakingly frustrating and can lead to messy code and overall bad project design. Thankfully, static elements are accessible from any context (i.e. anywhere in your script), so you can access these methods without needing to pass an instance of the class from object to object.
As you don’t need to declare an object instance to access static elements, you can be saved from unnecessary declarations to access seemingly simple functions.
Static elements are available in every instance of a class, so you can set values that you want to be available to all members of a type.
From the above example test1.php
helloworld() function cannot be overriden or overloaded since you have added a static keyword.
However in the second example, test2.php
helloworld() function can be overloaded and overriden
Illustration:1 (Works)
<?php
class Foo {
function helloWorld() {
print "Hello world " ;
}
}
class Foo1 extends Foo
{
function helloWorld()
{
echo "Foo's World";
}
}
$Foo1 = new Foo1();
$Foo1->helloWorld(); //Foo's World
Illustration:2 (Fails)
Cannot make static method Foo::helloWorld() non static
<?php
class Foo {
static function helloWorld() {
print "Hello world " ;
}
}
class Foo1 extends Foo
{
function helloWorld()
{
echo "Foo's World";
}
}
$Foo1 = new Foo1();
$Foo1->helloWorld();
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.
Why would PHP allow nesting functions?
<?php
function foo() {
function bar() {
return "bar";
}
return "foo";
}
print foo();
print bar();
.. is valid PHP.
But:
Why would nesting be needed ever?
And even if so, why can I call bar from anywhere (and not, e.g. only withing foo(), or trough foo.bar() or such).
I ran into this today, because I forgot a closing bracket somewhere, and had one too many further down. The code was valid and no errors thrown; but it all started acting really weird. Functions not being declared, callbacks going berserk and so on.
Is this a feature, and if so, to what purpose? Or some idiosyncrasy?
ANSWER: commentor points out that this is a duplicate of What are php nested functions for.
Note that the order is important here; you cannot call bar() before calling foo() in your example. The logic here appears to be that the execution of foo() defines bar() and puts it in global scope, but it's not defined prior to the execution of foo(), because of the scoping.
The use here would be a primitive form of function overloading; you can have your bar() function perform different operations depending upon which version of foo() declares it, assuming of course that each different version of foo() indeed defines a bar() function.
In PHP you can define functions, run-time constants and even classes conditionally. This allows you to define different functions / constants / classes depending on the circumstances.
Simply example: Define the String\Length function depending on whether multibyte support is turned on or off in your application.
namespace String;
if (\MULTIBYTE_MODE) {
function Length($string) {
return strlen($string);
}
} else {
function Length($string) {
return mb_strlen($string);
}
}
Nested functions are only a special case of conditional function definition.
I've been implementing a certain plugin (dtabs) on my page in Wordpress but after upgrading to the latest version, I found that I now have an error the 2nd time I call the main function called dtab_list_tabs().
The way it works is, the plugin gets include_once'd but the main function is called however many times you want to place tabs in your layout. I have 2 such calls to dtab_list_tabs().
Now, the problem is, for whatever reason the developer decided to include another function directly inside dtab_list_tabs() called current_tab(). Because it's declared within a function, apparently PHP tries to redeclare it as soon as you call the parent function the 2nd time, which doesn't make any sense to me.
PHP Fatal error: Cannot redeclare current_tab() (previously declared in .../wp-content/plugins/dtabs/dtabs.php:1638) in .../wp-content/plugins/dtabs/dtabs.php on line 1638
The code for that revision is at http://plugins.svn.wordpress.org/!svn/bc/208481/dtabs/trunk/dtabs.php
What I'm trying to figure out is whether there is a way to tell PHP that yeah... it has an internal function, which is a perfectly valid PHP paradigm as far as I know, so don't redeclare it and fail.
As for the situation at hand, I have removed current_tab() as it doesn't appear to be used.
You can use function_exists() to test if a function with that name has already been defined. If you make the definition conditional ( if(something) { function foo() {...} } ) php will "evaluate" the definition only when the condition is met.
function foo() {
if ( !function_exists('bar') ) {
function bar() {
echo 'bar ';
}
}
bar();
}
foo();
foo();
see also: http://docs.php.net/functions.user-defined
(But I'd try to avoid such things all together)
You can wrap your function declaration in an if statement. Use function_exists() to see if the function has been previously declared or not.
if(!function_exists('current_tab')) {
function current_tab() {
myMagicCode();
}
}
You can try this:
if (!function_exists('my_function')) {
function my_function() {
}
}
function_exists() - Return TRUE if the given function has been defined