I'm using PHP's global declaration to make an array available to a number of functions in a script. The variable is declared at the top of the script and is referenced with global in each of the functions which uses it, as follows:
<?php
$myarray = array(1, 2, 3);
function print_my_array() {
global $myarray;
print '<ul>';
foreach($myarray as $entry) {
print '<li>'.$entry.'</li>';
}
print '</ul>';
return 0;
}
print_my_array();
?>
Sometimes, but not always, the array is not set when the function is called, generating an error when the foreach is called. In the actual code, the array used is given a very unique name and so should not be causing any collisions with anything else. Am I mis-using the global declaration?
No, the snippet is correct. The problem you're having is the problem of using global variables – they can be accessed and changed from anywhere (perhaps accidental), thereby creating hard-to-find bugs.
By using globals you can hit quite a few gotchas, they'll also make you code less reusable.
Here's an example of your function which can be re-used many times across the site.
(untested)
<?php
function arrayTags($items, $open = '<li>', $close = '</li>')
{
if (is_array($items) && count($items) != 0)
{
$output = null;
foreach ($items as $item) {
$output .= $open . $item . $close;
}
return $output;
}
else
{
return '';
}
}
// Default, <li>
echo '<ul>' . arrayTags($myarray) . '</ul>';
// or, spans:
echo '<div id="container">' . arrayTags($myarray, '<span>', '</span>') . '</div>';
The least you could do is check if the array is null at the top of the function, before you run the foreach. that would at least prevent the error:
function print_my_array() {
global $myarray;
if(!empty($myarray)) {
print '<ul>';
foreach($myarray as $entry) {
print '<li>'.$entry.'</li>';
}
print '</ul>';
}
}
Also, I wouldn't just return 0 for the hell of it. You may want to incorporate whether or not the array was empty into what you return from this function.
$myarray = array(1, 2, 3);
In short you have to only declare it like so:
$myarray = array();
and if you want to populate it with values do that in the class constructor:
public function __construct(){
$myarray = array(1,2,3);
}
I'm no guru, but in my experience it seems that php doesn't like to execute function calls outside of a function within a class.
THIS DOES NOT WORK:
class MyClass {
public $mystring = myfunction();
public function myFunction(){
return true; //and your function code
}
}
so when you use array() it doesn't actually trigger any function call, it just creats an empty variable of type array. when you use array(1,2,3), it has to effectively run the 'create array' which is like a function.
I know annoying, I'd like it to be different, but I don't know a way of doing what you want in php. Let me know if there is a nice way I'd love to hear it!
Related
I need to pass a function as a parameter to another function and then call the passed function from within the function...This is probably easier for me to explain in code..I basically want to do something like this:
function ($functionToBeCalled)
{
call($functionToBeCalled,additional_params);
}
Is there a way to do that.. I am using PHP 4.3.9
Thanks!
I think you are looking for call_user_func.
An example from the PHP Manual:
<?php
function barber($type) {
echo "You wanted a $type haircut, no problem";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
?>
function foo($function) {
$function(" World");
}
function bar($params) {
echo "Hello".$params;
}
$variable = 'bar';
foo($variable);
Additionally, you can do it this way. See variable functions.
In php this is very simple.
<?php
function here() {
print 'here';
}
function dynamo($name) {
$name();
}
//Will work
dynamo('here');
//Will fail
dynamo('not_here');
I know the original question asked about PHP 4.3, but now it's a few years later and I just wanted to advocate for my preferred way to do this in PHP 5.3 or higher.
PHP 5.3+ now includes support for anonymous functions (closures), so you can use some standard functional programming techniques, as in languages like JavaScript and Ruby (with a few caveats). Rewriting the call_user_func example above in "closure style" would look like this, which I find more elegant:
$barber = function($type) {
echo "You wanted a $type haircut, no problem\n";
};
$barber('mushroom');
$barber('shave');
Obviously, this doesn't buy you much in this example - the power and flexibility comes when you pass these anonymous functions to other functions (as in the original question). So you can do something like:
$barber_cost = function($quantity) {
return $quantity * 15;
};
$candy_shop_cost = function($quantity) {
return $quantity * 4.50; // It's Moonstruck chocolate, ok?
};
function get_cost($cost_fn, $quantity) {
return $cost_fn($quantity);
}
echo '3 haircuts cost $' . get_cost($barber_cost, 3) . "\n";
echo '6 candies cost $' . get_cost($candy_shop_cost, 6) . "\n";
This could be done with call_user_func, of course, but I find this syntax much clearer, especially once namespaces and member variables get involved.
One caveat: I'll be the first to admit I don't know exactly what's going on here, but you can't always call a closure contained in a member or static variable, and possibly in some other cases. But reassigning it to a local variable will allow it to be invoked. So, for example, this will give you an error:
$some_value = \SomeNamespace\SomeClass::$closure($arg1, $arg2);
But this simple workaround fixes the issue:
$the_closure = \SomeNamespace\SomeClass::$closure;
$some_value = $the_closure($arg1, $arg2);
You could also use call_user_func_array(). It allows you to pass an array of parameters as the second parameter so you don't have to know exactly how many variables you're passing.
If you need pass function with parameter as parameter, you can try this:
function foo ($param1){
return $param1;
}
function bar ($foo_function, $foo_param){
echo $foo_function($foo_param);
}
//call function bar
bar('foo', 'Hi there'); //this will print: 'Hi there'
phpfiddle example
Hope it'll be helpful...
If you want to do this inside a PHP Class, take a look at this code:
// Create a sample class
class Sample
{
// Our class displays 2 lists, one for images and one for paragraphs
function __construct( $args ) {
$images = $args['images'];
$items = $args['items'];
?>
<div>
<?php
// Display a list of images
$this->loop( $images, 'image' );
// notice how we pass the name of the function as a string
// Display a list of paragraphs
$this->loop( $items, 'content' );
// notice how we pass the name of the function as a string
?>
</div>
<?php
}
// Reuse the loop
function loop( $items, $type ) {
// if there are items
if ( $items ) {
// iterate through each one
foreach ( $items as $item ) {
// pass the current item to the function
$this->$type( $item );
// becomes $this->image
// becomes $this->content
}
}
}
// Display a single image
function image( $item ) {
?>
<img src="<?php echo $item['url']; ?>">
<?php
}
// Display a single paragraph
function content( $item ) {
?>
<p><?php echo $item; ?></p>
<?php
}
}
// Create 2 sample arrays
$images = array( 'image-1.jpg', 'image-2.jpg', 'image-3.jpg' );
$items = array( 'sample one', 'sample two', 'sample three' );
// Create a sample object to pass my arrays to Sample
$elements = { 'images' => $images, 'items' => $items }
// Create an Instance of Sample and pass the $elements as arguments
new Sample( $elements );
I am writing some PHP code that would generate HTML files from templates.
I would like, if possible, to make a function that would take any strings I feed the function with, and put that into the file. Like so:
function generator($a, $b, $c, $n...){
$filename = $a . ".html";
ob_start ();
echo $b;
echo $c;
echo $d;
echo $n...;
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
I need this, because different pages would have different number of include files, and with this I would be able to skip making different functions for specific pages. Just an iterator, and that's it.
Thanks!
From PHP 5.6+ you can use ... to indicate a variable number of arguments:
function test (... $args)
{
foreach ($args as $arg) {
echo $arg;
}
}
test("testing", "variable"); // testing variable
Demo
Variable-length argument lists from the manual
So, your function would look something like this:
function generator($a, $b, $c, ... $n) {
$filename = $a . ".html";
ob_start();
echo $b;
echo $c;
foreach ($n as $var) {
echo $var;
}
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
You can also use variadic functions (PHP 5.6+) :
function generator($a, ...$args) {
echo $a . "\n";
print_r($args);
}
generator("test", 1, 2, 3, 4);
Outputs :
"test"
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
You can make it using an array as following :
function generator($array){
// set the first item of the array as name of the .html file and take it out of the array.
$filename = array_shift($array) . ".html";
ob_start ();
// echo all the array fields
foreach($array as $a){
echo $a;
}
$buffer = ob_get_clean();
file_put_contents($a, $buffer);
}
You can pass the array directly to call the function like the following :
generator( ["val_1", "val_2", "val_3"] );
Just use func_get_args(); inside your function to return an array of all arguments passed in.
You can also use func_get_arg($arg_num) to return a specific argument, or func_num_args to return the number of arguments.
All PHP functions allow any number of parameters, they just won't be callable by name, the only way is with these 3 functions.
Note, you may use a variadic argument as the last in the parameter list like so:
function my_func($x,$y, ... $z){
//Now $z is an array of all arguments after the first two
}
In the process of good design, I would think carefully about when and where to use things such as this. For example I currently work on a project that probably has over 200K lines of code and for better of worse this is actually never used.
The most common way is to pass an array "struct" to the method:
$args = array();
$args['kitchen'] = 'sink';
$args['bath'] = 'room';
$args['cat'] = array('fur','tail');
$func->someFunction($args);
If you wanted to have more control over the data you could create a struct and access that within the class. Public functions act as handlers.
class SomeClass {
....
private $args
public function setArgs($arg1,$arg2,$arg3) {
$this->arg1 = $arg1;
...
}
public function getArgs() {
return $this->args;
}
More rarely you can have C++ like control where you use a class just as a struct:
class MyStruct {
public $foo;
public $bar;
private $secret;
private function getSecret() {
return $secret;
}
protect function setSecret($val) {
$secret = $val;
}
}
Already mentioned is '...' which I nearly never see but it's interesting, though how useful ? Does this help explain what is going on?
function someFunction(... $args)
Usually you will see a mix of things in methods which helps articulate the purpose of it.
private function someSmallFunc($list = array(), $val = '', $limit = 10)
This example is to illustrate the natural grouping of information, data is in a list, $val is used for something to control the method along with $limit say limits the number of query results. Hence, you should think in this way about your methods IMO.
Also if you notice default values are set ($limit = 10) to in case they aren't passed in. For example if you call someSmallFunc($data, $someVal) (opposed to say someSmallFunc($data, $someVal, 20) ) and not pass in $limit it will default to 10.
I am having trouble returning a value from a multidimensional array using a key ONLY when I externalize to create a function.
To be specific, the following code will work when inline in a page:
<?php
foreach ($uiStringArray as $key) {
$keyVal = $key['uid'];
if($keyVal == 'global001') echo $key['uiString'];
}
?>
However, if I externalize the code as a function, like so:
function getUIString($myKey) {
// step through the string array and find the key that matches the uid,
// then return uiString
$myString = "-1";
foreach ($uiStringArray as $key) {
$keyVal = $key['uid'];
if($keyVal == 'global001') {
$myString = $key['uiString'];
}
}
return $myString;
}
And then call it like this:
<?php getUIString('global001'); ?>
It always returns -1, and will do so even if I use an explicit key in the function rather than a variable. I can't understand why this works inline, but fails as a function.
I'm a relative PHP noob, so please forgive me if this includes a glaring error on my part, but I've searched all over for discussion of this behavior and found none.
All help appreciated.
i think you need to take a look at PHP's Variable Scope. To problem is that PHP isn't typical of other languages where a variable defined outside of a function is visible within. You need to use something like the $GLOBALS variable or declare the variable global to access it.
To better illustrate, picture the following:
$foo = "bar";
function a(){
// $foo is not visible
echo $foo;
}
function b(){
global $foo; // make $foo visible
echo $foo;
}
function c(){
// acccess foo within the global space
echo $GLOBALS['foo'];
}
The same is basically holding true for your $uiStringArray variable in this scenario.
This is a problem with variable scope, see Brad Christie's answer for more details on variable scope.
As for your example, you need to either pass the array to the function or create it inside the function. Try:
function getUIString($myKey, $uiStringArray = array()) {
// step through the string array and find the key that matches the uid,
// then return uiString
$myString = "-1";
foreach ($uiStringArray as $key) {
$keyVal = $key['uid'];
if($keyVal == 'global001') {
$myString = $key['uiString'];
break;
}
}
return $myString;
}
And call the function using
<?php getUIString('global001', $uiStringArray); ?>
You are having this problem because you are overriding you $mystring variable even if it matches. Send your array as your parameter. It is unknown to your function.You just use break if variable matches
function getUIString($myKey, $uiStringArray=array()) {
// step through the string array and find the key that matches the uid,
// then return uiString
$myString = "-1";
foreach ($uiStringArray as $key) {
$keyVal = $key['uid'];
if($keyVal == 'global001') {
$myString = $key['uiString'];
break;
}
}
return $myString;
}
I need to create a column-system for Wordpress with shortcodes, which is not a problem, but I'm trying to make it with less code.
I have an array with the data needed, I loop through it, create a unique-named function and set it as shortcode-function. The third step is a mystery. How can I create a function from a variable.
Here's an example, how it should be done:
$data[] = "first";
$data[] = "second";
foreach($data as $key => $value) {
function $value($atts,$content) {
return '<div class="'.$value.'">'.$content.'</div>';
}
add_shortcode($value,$value);
}
However, it seems that it's not possible to make it work like that in PHP. Is there any way to make this work, as I would not want to write all the (identical) functions separated. I could make the shortcode something like [col first]text[/col] but the client wants to have different names for every one of them.
you can use the double dollar syntax to use the value of a variable as a variable identifier,
Example:
$variable = "test";
$$variable = "value of test"
echo $test; //or echo $$variable;
I have never tried but you way want to try:
foreach($data as $key => $value)
{
function $$value($atts,$content)
{
}
add_shortcode($value,$value);
}
or a function like create_function
if your using PHP 5.3 or greater then you can do something like so:
$$value = function()
{
}
which should work fine
I'm not sure how WP invocates the functions, but if it uses call_user_func then you might cheat by using an object with virtual methods:
class fake_functions {
function __call($name, $params) {
return '<div class="'.$name.'">'.$params[1].'</div>';
}
}
$obj = new fake_functions();
foreach ($data as $value) {
add_shortcode($value, array($obj,$value));
}
In my includes folder I have a function...
function storelistingUno() {
$itemnum=mysql_real_escape_string($_POST['itemnum']);
$msrp=mysql_real_escape_string($_POST['msrp']);
$edprice=mysql_real_escape_string($_POST['edprice']); //This value has to be the same as in the HTML form file
$itemtype=mysql_real_escape_string($_POST['itemtype']);
$box=mysql_real_escape_string($_POST['box']);
$box2=mysql_real_escape_string($_POST['box2']);
$box25=mysql_real_escape_string($_POST['box25']);
$box3=mysql_real_escape_string($_POST['box3']);
$box4=mysql_real_escape_string($_POST['box4']);
$box5=mysql_real_escape_string($_POST['box5']);
$box6=mysql_real_escape_string($_POST['box6']);
$box7=mysql_real_escape_string($_POST['box7']);
$box8=mysql_real_escape_string($_POST['box8']);
$itemcolor=mysql_real_escape_string($_POST['itemcolor']);
$link=mysql_real_escape_string($_POST['link']);
$test = "yes!";
}
I reference this in about 8 pages and I decided it would be easier to just make a function out of it and only touch this from now on. So I referenced storelistingUno(); in my code, but I don't think it worked, because I tried to execute echo $test; and nothing happened. Do I need to return something?
Thanks.
Look into extract(). You can do something like this:
<?php
function getEscapedArray()
{
$keys = array('itemnum', 'msrp', 'edprice', 'itemtype', 'box', 'box2', 'box25', 'box3', 'box4', 'box5', 'box6', 'box7', 'box8', 'itemcolor', 'link');
$returnValues = array();
foreach ($keys as $key) {
$returnValues[$key] = mysql_real_escape_string($_POST[$key]);
}
$returnValues['test'] = 'yes!';
return $returnValues;
}
extract(getEscapedArray());
echo $test;
Although - Its still not the best way to do this. The best would be to just use the return from that function as the array.
$parsedVals = getEscapedArray();
echo $parsedVals["test"];
If you absolutely need these variables a globals
function storelistingUno()
{
$desiredGlobals = array(
'itemnum'
,'msrp'
,'edprice'
,'itemtype'
,'box'
,'box2'
,'box25'
,'box3'
,'box4'
,'box5'
,'box6'
,'box7'
,'box8'
,'itemcolor'
,'link'
);
foreach ( $desiredGlobals as $globalName )
{
if ( isset( $_POST[$globalName] ) )
{
$GLOBALS[$globalName] = mysql_real_escape_string( $_POST[$globalName] );
}
}
}
$test is a local variable in that function - you either need to make it global (by putting global $test; at the start of the function or using $GLOBALS['test'] instead of just $test or return the value.
Are you thinking of using that function to just escape the values? Maybe you could make it perform the query too, then you wouldn't have to return / use globals.
Edit:
A different way would be to include the code instead of using a function - not recommended though...
You would have to mark every variable as global before you start to edit them within the function ... this isn't recommented since it's bad coding style but it might help you
$test = '';
function foo() {
global $test;
$test = 'bar';
}
echo $test; //prints nothing
foo();
echo $test; // prints "bar"