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.
Related
I want some functions to be not visible when required, but visible in the script they belong to.
For example:
required.php:
<?php
function privateFunction() {
echo 'from private function\n';
}
echo 'from required.php: ';
privateFunction();
index.php:
<?php
require './required.php';
echo 'from index.php: ';
privateFunction(); // I want this to give an error like "private function called outside the script it has been declared".
I have already tried making the function private, but it only gives a parse error.
required.php:
<?php
class A {
private function privateFunction() {
echo 'from private function\n';
}
}
This is a probably a bad idea in general (see comments above), but the following should do what you're asking.
It makes use of debug_backtrace() to grab the file name of the function then the file name of the function's caller, and compares them. If they don't match, it throws an exception:
function assertCalledByCurrentScript(): void
{
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
if (isset($backtrace[1]) && $backtrace[0]['file'] !== $backtrace[1]['file']) {
throw new \BadFunctionCallException("Cannot call {$backtrace[1]['function']} from outside of its defining script.");
}
}
Then use it like this:
function privateFunction()
{
assertCalledByCurrentScript();
// rest of your "private" function here
}
Basically only option you have is to hide private stuff inside class:
//Your file
class MyClass
{
public static function myAction()
{
$internalStuff = self::internalStuff();
return 'Using this function you can get what is inside internalStuff: ' . $internalStuff;
}
private static function internalStuff()
{
return 'Some internal stuff not accessible from outside';
}
}
function myAction()
{
return MyClass::myAction();
}
//Otherfile
//require yourfile.php
//You can only use `myAction` as function
echo myAction();
//Or call
echo MyClass::myAction();
//But you cannot use `internalStuff
echo MyClass::internalStuff();
I'm writing a PHP Wordpress plugin where I want to be able to call the functions I've defined in other parts of my website (e.g. on page templates).
I want to be able to pass arguments to my functions like so:
// Contained on Page Template to display content
$args1 = 'Hello';
$args2 = 'Goodbye';
saySomething( $args1, $args2);
// Contained within plugin file
function saySomething ($args1, $args2){
//echo $args1 //Test Only
//echo $args2 //Test Only
function sayHello () {
echo $args1;
}
function sayGoodbye () {
echo $args2;
}
}
I've already use 'include_once' to make sure I can call functions in my plugin file. However, for some reason the sub-functions (for want of a better word!) don't seem to work. I've tried a few things, including redefining the arguments within the first function (e.g. $newargs = $args1). Any thoughts greatly appreciated.
A couple of main things.
You've defined the sayHello and sayGoodbye functions, but they are not called.
sayHello and sayGoodbye refer to variables $args1 and $args2, but those variables are undefined within their scope.
Here's a way to make it work with minimal changes to your code. I changed the names of the variables to emphasize the fact that the variables in sayHello and sayGoodbye are not the same variables as the ones in saySomething.
function saySomething ($args1, $args2){
function sayHello ($x) { // update the function signature so that it takes an argument
echo $x; // use the given parameter
}
function sayGoodbye ($y) {
echo $y;
}
// call the functions
sayHello($args1);
sayGoodbye($args2);
}
One other thing:
Contrary to what it looks like, sayHello and sayGoodbye are available in the same scope as saySomething. They are not defined only within the scope of that function, even though they are written there. In effect it's the same thing as writing:
function saySomething ($args1, $args2){
sayHello($args1);
sayGoodbye($args2);
}
function sayHello ($x) {
echo $x;
}
function sayGoodbye ($y) {
echo $y;
}
To use inner functions in PHP, you have to pass scope explicitly:
$args1 = 'Hello';
$args2 = 'Goodbye';
$saySomething = function() use ($args1, $args2) {
$sayHello = function() use ($args1) {
echo $args1;
};
$sayGoodbye = function() use ($args2) {
echo $args2;
};
$sayHello();
$sayGoodbye();
};
It's not like JavaScript where the scope gets passed along automamagickally:
let args1 = 'Hello';
let args2 = 'Goodbye';
let saySomething = () => {
let sayHello = () => {
console.log(args1);
};
let sayGoodbye = () => {
console.log(args2);
};
sayHello();
sayGoodbye();
};
I am unable figure out how to make this work any help will be appreciated
<?php
class some{
function display()
{
$w ="its working";
$this->show($w);
}
function show($s)
{
echo $s;
}
}
?>
You were rightly advised to create an instance of your class then call the method on it but you said
see thats what i don't want .....i want some way to make it work without adding those two lines...by doing something else...just not that...and i can't figure out what i can do.
That something else is Simple! Make your method static
Declaring class properties or methods as static makes them accessible without needing an instantiation of the class.
public static function display()
{
$w ="its working";
self::show($w);
}
Then you can just do
some::display();
Fiddle
well it is working if you add the last two lines:
<?php
class some{
function display()
{
$w ="its working";
$this->show($w);
}
function show($s)
{
echo $s;
}
}
$x = new some;
$x->display();
?>
see here and click on "execute code"
Seems you are not called to display() function. Call to that function and try again.
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();
Example code:
class MyClass {
function echo_msg {
echo // now what...
}
function echo_from_inside {
$this->echo_msg()
}
}
result should be:
$my_instance = new MyClass();
$my_instance->echo_msg(); // I was called from OUTside
$my_instance->echo_from_inside(); // I was called from INside
It might be easier, rather than detecting from whence the function was called, to wrap a private function with a public one. Like so:
class MyClass{
private function myob(){
//do something
}
public function echo_msg(){
$this->myob();
//do other stuff like set a flag since it was a public call
}
private function foo(){ //some other internal function
//do stuff and call myob
$this->myob();
}
}
$obj=new MyClass();
$obj->echo_msg();//get output
$obj->myob(); //throws error because method is private
You can try and get the caller of your method:
$trace = debug_backtrace();
$caller = array_shift($trace);
echo 'called by '.$caller['function']
echo 'called by '.$caller['class']
this should work for you.
You could add an optional parameter like such:
function echo_msg($ins=false) {
if($ins){/*called from inside*/}else{/*called from outside*/}
echo // now what...
}
and leave that last. If you are calling it from inside the class, pass it true, otherwise pass nothing!