Not sure if this is due to a module I have installed or not, I've tried to remove all the extensions I have but this still doesn't work:
//test1.php
if(defined("TEST1")) {
return;
}
define("TEST1",1);
function test() {}
//test2.php
if(defined("TEST1")) {
return;
}
define("TEST1",1);
function test() {}
//test.php
include_once('test1.php');
include_once('test2.php');
test();
Results in a duplicate definition error. It looks like other checks like function_exists will work, but it's a bit messier to use.
According to PHP documentation (http://php.net/manual/en/functions.user-defined.php):
Functions need not be defined before they are referenced, except when a function is conditionally defined
It means that if you don't put your test() function into conditional statement it will be defined BEFORE script execution start.
To allow referencing functions that are defined further in the code, PHP at first searches the file for function (classes, etc) definitions, then runs the code. So when you're doing your:
if(defined('TEST1')) return;
Te function already exists and dupplicate error is triggered. The solution is to put them in any conditional statement (it does not have to make sense) or even just in braces. Functions defined in that manner will not be defined before script execution and also you won't be able to use them befere they are defined. You can fix your code just by doing this:
//test1.php
if(defined("TEST1")) {
return;
}
define("TEST1",1);
{
function test() {}
}
//test2.php
if(defined("TEST1")) {
return;
}
define("TEST1",1);
{
function test() {}
}
//test.php
include_once('test1.php');
include_once('test2.php');
test();
To test the behavior you can play with that two code snippets. This one will work:
<?php
test();
function test() {
echo 'Hello world!';
}
But this will fail with undefined function:
<?php
test();
{
function test() {
echo 'Hello world!';
}
}
While this again will work:
<?php
{
function test() {
echo 'Hello world!';
}
}
test();
Try
//test1.php
if(!defined("TEST1")) {
define("TEST1",1);
function test() {}
}
//test2.php
if(!defined("TEST1")) {
define("TEST1",1);
function test() {}
}
//test.php
include_once('test1.php');
include_once('test2.php');
test();
Related
It appears that PHP normally requires nested functions to be defined before usage. But code built dynamically with require doesn't have the same restriction. Can anyone explain why the inconsistency?
EDIT: Just to clarify, what I want to understand is: why does example 2 work instead of failing like example 1?
Example 1
If this is the contents of file nested1.php:
<?php
function outer() {
inner();
function inner() {
print "Hello world.\n";
}
}
outer();
?>
Running this with php nested1.php returns:
PHP Fatal error: Call to undefined function inner() in nested1.php on line 3
However, if you move the inner() function call below the function definition like this:
<?php
function outer() {
function inner() {
print "Hello world.\n";
}
inner();
}
outer();
?>
and run again you get:
Hello world.
Example 2
If this is the contents of nested2.php:
<?php
function outer() {
require "inner.php";
}
outer();
?>
And this is the contents of inner.php:
<?php
inner();
function inner() {
print "Hello world.\n";
}
?>
Running this with php nested2.php returns:
Hello world.
When outer() function is called first time, the inner() function inside of it will get declared in global scope.
function outer() {
function inner() {
print "Hello world.\n";
}
inner();
}
outer();
outer();//Second call
Thus you'll get the following error:
Fatal error: Cannot redeclare inner()
because the second call to outer() tried to re declare inner() function.
In order to avoid this issue, you need to use anonymous function declaration like following:
function outer() {
$inner = function () {
print "Hello world.\n";
};
$inner();
}
outer();
outer();
In this case $inner available only in local function "outer" scope
Example 1:
PHP does not support nested functions. It only supports inner functions.
Nested function reference
Inner function reference
<?php
function outer() {
inner();
function inner() {
print "Hello world.\n";
}
}
outer();
Example 2: In this function you are just requiring file which includes and evaluates the scripts. Reference
<?php
function outer() {
require "inner.php";
}
outer();
?>
<?php
inner();
function inner() {
print "Hello world.\n";
}
?>
In your first example, you are trying to define a new function inside another function, but nested functions are not allowed by php. Doing something like this would be fine:
<?php
function outer() {
inner();
}
outer();
function inner() {
print "Hello world.\n";
}
?>
In your 2nd example, you are including a file. As you are not using nested functions in inner.php, the code works as expected.
Example 1: Here I expect that function hello must be in the global scope.
But as per my expectation it does not behave same.It does not put function hello into global scope. at run time php must put function hello into global scope. It says undefined function hello().
$fruit=true;
foo();
hello();
function foo()
{
echo "you are in the foo<br/>";
}
if($fruit)
{
function hello()
{
echo "you are in the hello<br/>";
}
}
Example 2 : Now as after example 1 , i supposed the below script must also work as example 1. i supposed it will give also error undefined function bar(). But now here it behave differently and execute bar.
foo();
bar();
function foo()
{
function bar()
{
echo "I don't exist until foo() is called.\n";
}
}
So i am unable to get the concept how php interpreter behave internally. How does it parse the program, and does it execute the step one by one , or whole program at once?
I quote a manual for you:
When a function is defined in a conditional manner .... Its definition must be processed prior to being called.
And more:
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.
Example One:
You do not define the function hello() until a part of the script has run, its in an IF and therefore does not get defined until after you attempt to call it
Like this you get no errors as the IF is run before the now defined funtion hello is called. And of corse either way it is in the GLOBAL scope. But your way it didnt exist anywhere until after you called it.
<?php
$fruit=true;
if($fruit)
{
function hello()
{
echo "you are in the hello<br/>";
}
}
foo();
hello();
function foo()
{
echo "you are in the foo<br/>";
}
Same function name in different isolated classes is not allowed?
What am I doing wrong?
I reduced my real code to the minimum required to make some test.
Here it is:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
class confFunctions {
function getConf() {
function doWork() {
echo "I am from confFunctions!<br />";
}
doWork();
}
}
class thePage {
function loadPage() {
function doWork() {
echo "I am from thePage!<br />";
}
doWork();
}
}
// Start check.
echo "Checking...<br />";
$conf = new confFunctions();
$conf->getConf();
$page = new thePage();
$page->loadPage();
?>
The output is:
Checking...
I am from confFunctions!
Fatal error: Cannot redeclare doWork() (previously declared in /var/www/Test2/index.php:11) in /var/www/Test2/index.php on line 23
Renaming one of the shared-name functions makes all working well. That is, changing doWork to doWork1 in the second class, like this:
class thePage {
function loadPage() {
function doWork1() {
echo "I am from thePage!<br />";
}
doWork1();
}
}
gives correct results:
Checking...
I am from confFunctions!
I am from thePage!
Should not what is inside a class be visible only to that class, if not declared public?
By declaring a function in a function, you are actually declaring the second function into the global scope.
If you want your functions to be limited to the class scope, don't declare a function in another function, but rather declare them under each other.
Consider this code that declares a function in another function (in a class):
<?php
class MyFunctions {
function load() {
function doWork() {
echo "I am doing my work from global scope";
}
}
}
$mf = new MyFunctions();
$mf->load();
// $mf->doWork(); <-- won't work here
doWork(); // <-- this will work!
?>
Now consider this code that declares a function under another function (in a class).
<?php
class MyFunctions {
function load() {
//...
}
function doWork() {
echo "I am doing my work from class scope";
}
}
$mf = new MyFunctions();
// $mf->load(); <-- not really important anymore
$mf->doWork(); // <-- this will work now
// doWork(); <-- won't work here anymore
?>
Function scope is always namespace wide when declaring a named function.
You'll need to assign it to a variable to constrain it to a specific scope ($doWork = function() { }).
You seem to be going down an odd path though. Perhaps you should just use a private method?
Full example just to make it clear:
class confFunctions {
function getConf() {
$doWork = function() {
echo "I am from confFunctions!<br />";
};
$doWork();
}
}
class thePage {
function loadPage() {
$doWork = function() {
echo "I am from thePage!<br />";
};
$doWork();
}
}
I dont think you meant to nest the functions ? and your calling them from the global scope.
something like this is likely what you meant
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
class confFunctions {
function getConf() {
$this->doWork();
}
function doWork() {
echo "I am from confFunctions!<br />";
}
}
class thePage {
function loadPage() {
$this->doWork();
}
function doWork() {
echo "I am from thePage!<br />";
}
}
// Start check.
echo "Checking...<br />";
$conf = new confFunctions();
$conf->getConf();
$page = new thePage();
$page->loadPage();
?>
First guess would be that somehow you aren't properly closing your class from the first example. Different classes are definitely allowed to have the same function names, so there's something else going on in your code here that's not being shown through the psuedo-code you're posting.
UPDATE:
As NL-X said, by posting the function inside of a class function it then creates it in global scope. Thank you for updating your pseudo-code with actual examples.
Is it possible to add methods to functions?
For example:
<?
function func(){
;
}
//add method
func->test = function(){
;
}
func->test();
func();
I'm coming from a javascript background, and therefore I'm used to 'everything is an object'.
EDIT:
I was just explaining where the misconception may often come from for new phpers. I understand the above code doesn't work.
EDIT 2
Figured it out.
class myfunc_class{
function __invoke(){
//function body
}
function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$func = new myfunc_class;
$func->test = function(){
echo '<br>test<br>';
};
$func->test();
$func();
Even sexier :)
class func{
public $_function;
function __invoke(){
return call_user_func_array($this->_function,func_get_args());
}
function __construct($fun){
$this->_function = $fun;
}
function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$func = new func(function($value){
echo $value;
});
$func->method = function(){
echo '<br>test<br>';
};
$func('someValue');
$func->method();
No.
Not everything is an object in PHP. In fact the only thing that is an object is, well, an object. More specifically, and generally, an instantiation of a class.
Your code converted to PHP
// function_object.php
<?php
class FunctionObject {
public method func() {
// do stuff
}
}
?>
In other code you would use it like this:
<?php
// example.php in same folder as function_object.php
include 'function_object.php';
$FuncObj = new FunctionObject;
$FuncObj->func();
Also: read more about PHP & OOP
No, because an object is a different PHP language construct than a function. Functions do not have properties, but are instead simply execution instructions.
But, if func were instead a pre-defined class, then yes... with a bit of witchcraft, ignoring public outcry, foregoing readability and PHP coding standards, and by using closures with the __call() magic method...
class func
{
function __call($func, $args)
{
return call_user_func_array($this->$func, $args);
}
}
$obj = new func;
$obj->test = function($param1, $param2)
{
return $param1 + $param2;
};
echo $obj->test(1,1);
This won't work as you'd think without __call(), because by $obj->test(1,1), PHP thinks you're trying to call a non-existent method of func when out of object scope. But inside, being that the new "test" property is of a type: closure, the call_user_func_array() just sees the "test" property as just another function, so you can hide this bit of trickery from outside scope.
You would need your function func() to return an object, then you'd be able to do something like: func()->test();
But please note that your way of handling objects is not right in PHP and I suggest that you go read the OO documentations here.
In difference to javacript, in PHP not everything is an object. Therefore you need to differ between function and class.
If you want to create an object, you need to define the class first.
class myClass {
}
You can then add as many functions to the class as you need. But you need to define them first:
class myClass {
function test() {
echo "test!\n";
}
}
When everything is ready, you can bring it to life then:
$class = new myClass;
$class->test();
Checkout the manual for more.
You can't do what you're trying to do, but you can define functions inside of other functions.
This example outputs text:
function a() {
function b() { echo 'Hi'; }
}
a();
b();
Output: HiHi
This example outputs an error:
function a() {
function b() { echo 'Hi'; }
}
b();
Output: ERROR
Snippet 1 works. Snippet 2 doesn't. Why?
1.
foo();
function foo()
{
// do soemething
}
2.
foo();
if(!function_exists("foo"))
{
function foo()
{
// do soemething
}
}
See http://www.php.net/manual/en/functions.user-defined.php:
Functions need not be defined before
they are referenced, except when a
function is conditionally defined [...]
Its definition must be processed prior
to being called.
You're trying to execute foo() before testing to see whether it's defined or not (and subsequently defining it)
if(!function_exists("foo"))
{
function foo()
{
// do soemething
}
}
foo();