turning variable into class variable - php

In my PHP class I have
public $a;
public $b;
public $c;
public $d;
and I set there values in the construct.
I am now attempting to write a update function, and i'm trying to check if they are updating, say $a, to be the same as it is.
function update($what, $to) {
if ($to == $this->what) return false;
...
}
$updated = $instance->update($a, "Foobar");
if ($updated) echo "Updated";
else echo "You didn't change the value";
but since I know this line
if ($to == $this->what) return false;
is invalid, i'm seeking a new way to write it.
Ideas?
Thanks in advance

The solution to your dilemma are variable variables. Your update function must assign it like this:
$this->{$what} = $to;
The if-check would be correspondingly:
if ($to == $this->{$what}) return false;
And you cannot actually invoke the update() method with a variable $a. You must give it a variable name as string:
$instance->update("a", "Foobar");

You can do something like:
if ($to == $this->$what) return false;
And call it like this:
update("a", "Foobar");
This uses variable variables ( http://php.net/manual/en/language.variables.variable.php ).
You could also pass by reference:
function update(&$what, $to) {
if ($to == $what) return false;
...
}
And call it like you did in your example.

$this->$what should do the trick, if $what = 'a'
You generally want to avoid doing that though.

Related

PHP: Is it necessary to change variable names when passing them to a function?

I have a body function and a function called within the first one.
As can be seen below I don't change the parameters name while using in the second function.
Is it necessary to change the params names for use inside _display_bar();? What are the side effects if I don't?
function main_func($form, &$form_state, $key, $code) {
$output = '';
...
$output .= _display_navbar($trans, $status_names);
return $output
}
function _display_navbar($trans, $status_names) {
$trans = 'bla';
$status_names = 'another bla';
$bar = $trans . ':' .$status_names;
return $bar;
};
Variables have function scope. Unless you specifically declare otherwise, the names are only valid inside the function. They do not bleed into other scopes. There are no side effects. You don't need to use unique names.
It actually does not matter. But you better should not have the same names - it is confusing. Let me give you an example. $s will have 3 after the first function call to sum; 7 after the second function call to sum. The parameters did not have the same name as the function parameter names.
To answer your question fully - there are absolutely no side effects.
function main()
{
$a = 1;
$b = 2;
$s = sum($a, $b);
$d = 3;
$e = 4;
$s = sum($d, $e);
}
function sum($first, $second)
{
$ret = $first + $second;
return $ret;
}
Once a variable is passed to a function, the name of the variable is not important. Only the data is passed through. So your function could be this:
function _display_navbar($foo, $bar) {
$foo = 'bla';
return $bar;
}
And it will return what ever was passed as the second parameter regardless of what the variable name was.
The names you pass as function arguments must be in scope at the point they are called.
It doesn't matter if they have the same name as the formal function parameters, but you must recognise that just because they have the same name doesn't mean that brings them into scope.
So, in your code:
function main_func($form, &$form_state, $key, $code) {
$output = '';
...
$output .= _display_navbar($trans, $status_names);
the last line will be incorrect, unless $trans and $status_names are in scope at the time.

Default value if variable not sets

I sometimes have variables that might not be set and I would like to use a default parameter instead. Like here:
if ($p == "a") doSomething();
If $p is not defined PHP throws Notice: Undefined variable. To avoid this I often I used this construct in such a case:
$p = (isset($p) ? $p : "");
But that is ugly if you have to use it a lot. So I wrote a function for it:
function getIfSet(&$value, $default = '')
{
return isset($value) ? $value : $default;
}
// Example
if (getIfSet($p) == "a") doSomething();
I wonder if there is a PHP function for this or how you solve this.
Just a little improvement, prefer passing null value to $default, passing empty string can be confusing, cause correct value can be empty string.
function getIfSet(&$value, $default = null)
{
return isset($value) ? $value : $default;
}
$p = getIfSet($p);
isset() is about as clean as it gets. Although I must admit that I'm not too fond of defaulting to an empty string, simply because a variable could be an empty string, yet still "be set". I think that a default of bool false or null would be truer to the behavior of isset:
function getIfSet(&$value, $default = false)
{
return isset($value) ? $value : $default;
}
$p = getIfSet($p);
if($p !== false){
//insert or whatever
}
else{
header('Location: error.php');
exit;
}
Depending on what kind of values you're checking (maybe REQUEST data?), consider using classes. They are fun and they could be available anywhere.
Assuming you're checking POST data (if you don't, well, take this as an idea), create a class that checks this array:
class Post
{
public function __get($index)
{
if (isset($_POST[$index]))
return $_POST[$index];
else
return null;
}
}
As simple as that. You know that __get() will trigger when you try to access a non-existant property. In this case, if the property (actually, the index in the $_POST array) doesn't exist, null will be returned and no errors are generated.
Now you can do:
$params = new Post();
$foo = $params->name ?: ''; // of course this doesn't make much sense.
if (!$params->password) ...
// instead of
if (isset($_POST['password'])) ...
// you'll still have to use isset for cases like:
if (isset($_POST['user']['password']) ...
if (isset($params->user['password'])) ...
// but still looks neater I'd say
A problem you'll find soon is that $params isn't a super global variable, while $_POST are. How to solve this? Create it in the constructor of your controller class and use Dependency Injection for all other objects your are using.
I tried to make renocor's answer more clean and OOP when I came up with this solution:
class NiceArray implements ArrayAccess {
protected $array;
public function __construct(&$array) {
$this->array =& $array;
}
public function offsetExists($offset) {
return true;
}
public function offsetGet($offset) {
if (isset($this->array[$offset]))
{
return $this->array[$offset];
}
else
{
return null;
}
}
public function offsetSet($offset, $value) {
$this->array[$offset] = $value;
}
public function offsetUnset($offset) {
unset($this->array[$offset]);
}
}
Usage:
$get = new NiceArray($_GET);
if ($get['p'] == "a") doSomething();
I know the class is kind of big but this way you still have an array and you can easily use it for every array you want. You do not need to change any code you may had before. You can still access and change the data. It will even change the original array.

Pass variable number of params without call_user_func_array()

I have a code problem which stems from the fact that I am using certain libraries of code I cannot change.
I use the following code to pass execution of any undefined methods to another class, and it works fine but it seems like a waste doubling up.
Any suggestions?
Basically I want to know if it's possible to pass an unknown number of parameters to a method (without using call_user_func_array(), just in case they need to be passed by reference). I am not asking how to use func_get_args(), rather the reverse.
Or should I just allow for a few more arguments in the first logic path (the list() code)?
class Foo {
__construct() {
$this->external = new ClassThatIHaveNoControlOver();
}
function bar($name) {
return 'Hi '.$name;
}
function __call($method, $arguments) {
if (count($arguments) < 3) {
// call_user_func_array won't pass by reference, as required by
// ClassThatIHaveNoControlOver->foobar(), so calling the function
// directly for up to 2 arguments, as I know that foobar() will only
// take 2 arguments
list($first, $second) = $arguments + Array(null, null);
return $this->external->$method($first, $second);
} else {
return call_user_func_array(array($this->external, $method), $arguments);
}
}
}
$foo = new Foo();
$firstName = 'Bob';
$lastName = 'Brown';
echo $foo->bar($firstName); // returns Hi Bob as expected
echo $foo->foobar($firstName, $lastName); // returns whatever
// ClassThatIHaveNoControlOver()->foobar() is meant to return
EDIT
Just to clarify, I know I can use this method to rejig the parameters as references, but that would mean passing everything as a reference, even if the method didn't require it - something I was trying to avoid, but seems unlikely at the moment.
As commented in the thread question post's comments this is an example and not necessarily (likely) best practice.
//Some vars
$foo = "shoe";
$bar = "bucket";
//Array of references
$arr = Array(&$foo, &$bar);
//Show that changing variable value affects array content
$foo = "water";
echo $arr[0];
//Sample function
function fooBar($a)
{
$a[0] = "fire";
}
//Call sample function
call_user_func("fooBar",$arr);
//Show that function changes both array contents and variable value by reference
echo $arr[0];
echo $foo;
Expanding a bit on the discussion, again not the most industry standard approach but it'll do the job.
function pushRefOnArray(&$arr, &$var, $key = false)
{
if(isset($key))
$arr[$key] = &$var;
else
$arr[] = &$var;
}
Essentially you can dynamically build your array and call pushRefToArray() any time you need to pass an item to be passed as reference rather than by value.
You could use something like this:
public function __call($method, $params = array()) {
switch (count($params)) {
case 0:
return $this->external->{$method}();
case 1:
return $this->external->{$method}($params[0]);
case 2:
return $this->external->{$method}($params[0], $params[1]);
case 3:
return $this->external->{$method}($params[0], $params[1], $params[2]);
default:
return call_user_func_array(array(&this->external, $method), $params);
}
}

PHP function to check if a variable exist or not outside of a function

I am in need of a PHP function to check that a variable exist or not outside of function. If it does not exist, then assign a default value to it.
The function will be something like: function if_exist($argument, $default = '') where $argument will be any variable outside the function. It can be a variable's variable, and $default will be the default value of the variable if the variable doesn't exist.
Please avoid using global scope in the function, because I heard that it's not good for a site's security.
You can make $argument pass-by-reference:
function if_exist(&$argument, $default="") {
if(!isset($argument)) {
$argument = $default;
return false;
}
return true;
}
DEMO
I don't see why you want a function for this at all.
$a = isset($a) ? $a : "my default string";
Everybody will understand what your code does without resorting to little-known "features" of PHP and having to look at your functions body to see what it does.
Even though it may look like a function call, it's not. isset() is a language construct! That's why it will not raise a Notice.
There are two ways of going at this. You may be looking for the first non-null value or if the actual variable is set or not...
The first use-case is easy... To get the value of the first variable that isn't null, define a function as such:
function coalesce() {
$args = func_get_args();
if(is_array($args))
return null;
foreach($args as $arg) {
if($arg !== null)
return $arg;
}
return null;
}
Using this function is easy. Simply call coalesce() with a number of different arguments and it will always return the first non-null value it encounters.
$myVar = coalesce($myVar, null, 'Hello There', 'World');
echo $myVar; // Hello there
However, if you are looking for a function to check if a variable is defined, and if it isn't define it, then you need to create a function which forces the first argument to be a reference.
function set_default(&$variable, $defaultValue = null) {
if(!isset($variable)) {
$variable = $defaultValue;
return false;
}
return true;
}
Use this:
function setGlobalIfNotSet( $variableName, $defaultValue = false ) {
if ( ! isset( $variableName )) {
global $$variableName;
$$variableName = $defaultValue;
}
}
You can make a function to use isset:
function isset_default($v, $default = '') {
return isset($v) ? $v : $default;
}
Usage:
$v = isset_default($v, 'somedefaultvalue');

Accept function as parameter in PHP

I've been wondering whether it is possible or not to pass a function as a parameter in PHP. I want something similar to when you're programming the following code in JavaScript:
object.exampleMethod(function(){
// some stuff to execute
});
What I want is to execute that function somewhere in exampleMethod. Is that possible in PHP?
It's possible if you are using PHP 5.3.0 or higher.
See Anonymous Functions in the manual.
In your case, you would define exampleMethod like this:
function exampleMethod($anonFunc) {
//execute anonymous function
$anonFunc();
}
Just to add to the others, you can pass a function name:
function someFunc($a)
{
echo $a;
}
function callFunc($name)
{
$name('funky!');
}
callFunc('someFunc');
This will work in PHP4.
Valid: (PHP 4 >= 4.0.1, PHP 5, PHP 7)
You can also use create_function to create a function as a variable and pass it around. Though, I like the feeling of anonymous functions better. Go zombat.
Update 09 - Jan - 2022
Warning
This function has been DEPRECATED as of PHP 7.2.0, and REMOVED as of PHP 8.0.0. Relying on this function is highly discouraged.
Just code it like this:
function example($anon) {
$anon();
}
example(function(){
// some codes here
});
it would be great if you could invent something like this (inspired by Laravel Illuminate):
Object::method("param_1", function($param){
$param->something();
});
PHP VERSION >= 5.3.0
Example 1: basic
function test($test_param, $my_function) {
return $my_function($test_param);
}
test("param", function($param) {
echo $param;
}); //will echo "param"
Example 2: std object
$obj = new stdClass();
$obj->test = function ($test_param, $my_function) {
return $my_function($test_param);
};
$test = $obj->test;
$test("param", function($param) {
echo $param;
});
Example 3: non static class call
class obj{
public function test($test_param, $my_function) {
return $my_function($test_param);
}
}
$obj = new obj();
$obj->test("param", function($param) {
echo $param;
});
Example 4: static class call
class obj {
public static function test($test_param, $my_function) {
return $my_function($test_param);
}
}
obj::test("param", function($param) {
echo $param;
});
According to #zombat's answer, it's better to validate the Anonymous Functions first:
function exampleMethod($anonFunc) {
//execute anonymous function
if (is_callable($anonFunc)) {
$anonFunc();
}
}
Or validate argument type since PHP 5.4.0:
function exampleMethod(callable $anonFunc) {}
Tested for PHP 5.3
As i see here, Anonymous Function could help you:
http://php.net/manual/en/functions.anonymous.php
What you'll probably need and it's not said before it's how to pass a function without wrapping it inside a on-the-fly-created function.
As you'll see later, you'll need to pass the function's name written in a string as a parameter, check its "callability" and then call it.
The function to do check:
if( is_callable( $string_function_name ) ){
/*perform the call*/
}
Then, to call it, use this piece of code (if you need parameters also, put them on an array), seen at : http://php.net/manual/en/function.call-user-func.php
call_user_func_array( "string_holding_the_name_of_your_function", $arrayOfParameters );
as it follows (in a similar, parameterless, way):
function funToBeCalled(){
print("----------------------i'm here");
}
function wrapCaller($fun){
if( is_callable($fun)){
print("called");
call_user_func($fun);
}else{
print($fun." not called");
}
}
wrapCaller("funToBeCalled");
wrapCaller("cannot call me");
Here's a class explaining how to do something similar :
<?php
class HolderValuesOrFunctionsAsString{
private $functions = array();
private $vars = array();
function __set($name,$data){
if(is_callable($data))
$this->functions[$name] = $data;
else
$this->vars[$name] = $data;
}
function __get($name){
$t = $this->vars[$name];
if(isset($t))
return $t;
else{
$t = $this->$functions[$name];
if( isset($t))
return $t;
}
}
function __call($method,$args=null){
$fun = $this->functions[$method];
if(isset($fun)){
call_user_func_array($fun,$args);
} else {
// error out
print("ERROR: Funciton not found: ". $method);
}
}
}
?>
and an example of usage
<?php
/*create a sample function*/
function sayHello($some = "all"){
?>
<br>hello to <?=$some?><br>
<?php
}
$obj = new HolderValuesOrFunctionsAsString;
/*do the assignement*/
$obj->justPrintSomething = 'sayHello'; /*note that the given
"sayHello" it's a string ! */
/*now call it*/
$obj->justPrintSomething(); /*will print: "hello to all" and
a break-line, for html purpose*/
/*if the string assigned is not denoting a defined method
, it's treat as a simple value*/
$obj->justPrintSomething = 'thisFunctionJustNotExistsLOL';
echo $obj->justPrintSomething; /*what do you expect to print?
just that string*/
/*N.B.: "justPrintSomething" is treated as a variable now!
as the __set 's override specify"*/
/*after the assignement, the what is the function's destiny assigned before ? It still works, because it's held on a different array*/
$obj->justPrintSomething("Jack Sparrow");
/*You can use that "variable", ie "justPrintSomething", in both ways !! so you can call "justPrintSomething" passing itself as a parameter*/
$obj->justPrintSomething( $obj->justPrintSomething );
/*prints: "hello to thisFunctionJustNotExistsLOL" and a break-line*/
/*in fact, "justPrintSomething" it's a name used to identify both
a value (into the dictionary of values) or a function-name
(into the dictionary of functions)*/
?>
Simple example using a class :
class test {
public function works($other_parameter, $function_as_parameter)
{
return $function_as_parameter($other_parameter) ;
}
}
$obj = new test() ;
echo $obj->works('working well',function($other_parameter){
return $other_parameter;
});
Here is a simple procedural example of how you could implement validation of multiple data items using separate functions for each data item validation, passed as an array of functions argument to a master validations function, with the data to be validated (the arguments to the functions) passes as the other array argument to the master validation function. Useful for writing generic code to validate form data.
<?php
function valX($value) {
echo "<p>Validating $value == 5</p>";
if ($value == 5) {
return true;
} else {
return false;
}
}
function valY($value) {
echo "<p>Validating $value == 6</p>";
if ($value == 6) {
return true;
} else {
return false;
}
}
function validate($values, $functions) {
for ($i = 0; $i < count($values); $i++) {
if ($functions[$i]($values[$i])) {
echo "<p>$values[$i] passes validation</p>";
} else {
echo "<p>$values[$i] fails validation</p>";
}
}
}
$values = [5, 9];
$functions = ['valX', 'valY'];
validate($values, $functions);
?>

Categories