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();
};
Related
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 encapsulate, a variable or function let say, in PHP without wrapping them in a class? What I was doing is:
//Include the file containing the class which contains the variable or function
include('SomePage.php');
//Instantiate the class from "SomePage.php"
$NewObject = new SomeClassFromSomePage();
//Use the function or variable
echo $NewObject->SomeFuncFromSomeClass();
echo $NewObject->SomeVarFromSomeClass;
My intention is to avoid naming conflict. This routine, although it works, makes me tired. If I cannot do it without class, it is possible not to instantiate a class? and just use the variable or function instantly?
To use class methods and variables without instantiating, they must be declared static:
class My_Class
{
public static $var = 123;
public static function getVar() {
return self::var;
}
}
// Call as:
My_Class::getVar();
// or access the variable directly:
My_Class::$var;
With PHP 5.3, you can also use namespaces
namespace YourNamespace;
function yourFunction() {
// do something...
}
// While in the same namespace, call as
yourFunction();
// From a different namespace, call as
YourNamespace\yourFunction();
PHP Namespaces were made to archive the exact same goal:
<?php // foo.php
namespace Foo;
function bar() {}
class baz {
static $qux;
}
?>
When using call namespaced functions like this:
<?php //bar.php
include 'foo.php';
Foo\bar();
Foo\baz::$qux = 1;
?>
This is a way to encapsulate without Class
<?php
(function (){
$xyz = 'XYZ';
})();
echo $xyz; // warning: undefined
Encapsulation Alternative
With this method you can minimize unintentional using array key(uses it instead of variables). Can also use value stored in array anywhere after assigning. Shorter array key area length with variable in keys, inside encapsulation function; outside encapsulation function, variables can be used in keys but otherwise long discriptive keys. Nested encapsulation can also be used.
Example
<?php
define('APP', 'woi49f25gtx');
(function () {
$pre = 'functions__math__'; // "functions" is main category, "math" is sub.
$GLOBALS[APP][$pre . 'allowedNumbers'] = [3,5,6];
$GLOBALS[APP][$pre . 'square'] = function ($num) {
return $num * $num;
};
$GLOBALS[APP][$pre . 'myMathFunction'] = function ($num) use ($pre) {
if(in_array($num,$GLOBALS[APP][$pre . 'allowedNumbers'])) return 'not allowed';
return $GLOBALS[APP][$pre . 'square']($num);
};
})();
echo $GLOBALS[APP]['functions__math__myMathFunction'](4);
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
i have php with an array i.e
$var = array(
"var" => "var value",
"var2" => "var value1"
);
and have another file with a class i.e
class class1{
function fnc1(){
echo $var['var2'];
//rest of function here
}
}
now how can i get $var['var'] in class file in function fnc1()
You can pass it as an argument, or use the global keyword to put it in the current scope.
However, using global is discouraged, try passing it as an argument.
Pass it as an argument?
class class1{
function fnc1($var) {
echo $var['var2'];
}
}
And in your other file call this class method with your array as an argument.
From: http://php.net/manual/en/function.include.php
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
So you could do
class class1
{
function fnc1()
{
include 'thefile.php'
echo $var['var2'];
//rest of function here
}
}
but like others pointed out before, you dont want to do that, because it introduces a dependency on the filesystem in your class. If your method requires those variables to work, then inject them as method arguments or pass them into the constructor and make them a property (if you need them more often). This is called Dependency Injection and it will make your code much more maintainable in the long run, e.g. do
class class1
{
private $data;
public function __construct(array $var)
{
$this->data = $var;
}
function fnc1()
{
echo $this->data['var2'];
//rest of function here
}
}
and then do
$obj = new class1($var);
echo $obj->fnc1();
or require the data to be passed into the method on invocation
class class1
{
function fnc1(array $var)
{
echo $var['var2'];
//rest of function here
}
}
and then
$obj = new class1;
$obj->fnc1($var);
You might use global $var in your included file, but it's really a bad practice, as another script, before your included file, might redefine the value/type of $var.
Example :
class class1{
function fnc1(){
global $var;
echo $var['var2'];
//rest of function here
}
}
A better solution, is to pass your $var as a parameter to your fnc1(), even to your class1::__construct()
#Vindia: I'd prefer the argumant-style too, but would recommend either using type hint or a simple check to avoid warnings when accessing *non_array*['var2']:
// acccepts array only. Errors be handled outside
function fnc1(Array $var) {
echo $var['var2'];
}
// accepts any type:
function fnc1(Array $var) {
if (is_array($var)) {
echo $var['var2'];
}
}
class class1{
function fnc1(){
include 'otherFile.php';
echo $var['var2'];
//rest of function here
}
}
Is it possible to access outer local varialbe in a PHP sub-function?
In below code, I want to access variable $l in inner function bar. Declaring $l as global $l in bar doesn't work.
function foo()
{
$l = "xyz";
function bar()
{
echo $l;
}
bar();
}
foo();
You could probably use a Closure, to do just that...
Edit : took some time to remember the syntax, but here's what it would look like :
function foo()
{
$l = "xyz";
$bar = function () use ($l)
{
var_dump($l);
};
$bar();
}
foo();
And, running the script, you'd get :
$ php temp.php
string(3) "xyz"
A couple of note :
You must put a ; after the function's declaration !
You could use the variable by reference, with a & before it's name : use (& $l)
For more informations, as a reference, you can take a look at this page in the manual : Anonymous functions
You must use the use keyword.
$bar = function() use(&$l) {
};
$bar();
In the very very old PHP 5.2 and earlier this didn't work. The syntax you've got isn't a closure, but a definition of a global function.
function foo() { function bar() { } }
works the same as:
function foo() { include "file_with_function_bar.php"; }
If you execute function foo twice, PHP will complain that you've tried to re-define a (global) function bar.
You can read default value by:
function(){
return preg_match(
"yourVar = \d+"
, str_file_get_contents(functionFile)
, arrayToPutFieldsValue
);
}
If You would use two functons in the same time - it's like someone's using a spoon and You want to take a food from that spoon - You'll waste a food or some of You will starv.
Anyway - You would have to set a pointer somehow in a hard way.
It's impossible to get any field from other function or class without calling it to life.
Functions/methods are instance-like - they need to be called.
Share the common fields by accessing a global fields with synchronized functions.
function a()
{
function val1($arg=null)
{
static $a;
if ($arg !== null) $a = $arg;
else return $a;
}
function b()
{
val1('1234');
echo val1() . '<br>'; // shows: 1234
val1('my custom data');
echo val1() . '<br>'; // shows: my custom data
}
b();
}
a();
Used val1('my custom data') to set my value
Used val1() to get my value