Only initialize a variable in an array if it's requested - php

Here's a little mock-up to describe my predicament:
<?php
$var = "Before";
function getVar(){
global $var;
return $var;
}
$array = Array(
"variable" => "Var = " . getVar()
);
$var = "After";
echo $array['variable'];
?>
That code would echo 'Before', I'm aiming for it to echo 'after'. I realize that this is how PHP is supposed to work however it's crucial for the array to execute getVar() only when it's called.
How would I go about doing this?

You can not do this since array declaration will initialize it - so you're mixing function calling at array's 'usage' and at it's definition. There's no 'usage': array is already defined to that moment.
However, an answer could be using ArrayAccess, like this:
class XArray implements ArrayAccess
{
private $storage = [];
public function __construct()
{
$this->storage = func_get_args();
}
public function offsetSet($offset, $value)
{
if(is_null($offset))
{
$this->storage[] = $value;
}
else
{
$this->storage[$offset] = $value;
}
}
public function offsetExists($offset)
{
return isset($this->storage[$offset]);
}
public function offsetUnset($offset)
{
unset($this->storage[$offset]);
}
public function offsetGet($offset)
{
if(!isset($this->storage[$offset]))
{
return null;
}
return is_callable($this->storage[$offset])?
call_user_func($this->storage[$offset]):
$this->storage[$offset];
}
}
function getVar()
{
global $var;
return $var;
}
$var = 'Before Init';
$array = new XArray('foo', 'getVar', 'bar');
$var = 'After Init';
var_dump($array[1]);//'After Init'
-i.e. try to call data, which is inside element, when actual get happened. You may want to have different constructor (for associative arrays) - but the general idea was shown.

Editing my answer after the question was edited.
No, what you are trying to achieve isn't possible because when you call the function it returns and it's done at that point. But you could achieve something similar with object oriented coding. I'll create something for you, please wait.
<?php
class Foo {
public function __toString() {
global $var;
return "Var = {$var}";
}
}
$var = "Before";
$array = array( "variable" => new Foo() );
$var = "After";
echo $array['variable'];
?>
PS: Sorry for the late answer, but there was a blackout in Salzburg. :(

It occurred to me that you could also use anonymous functions and invoke/execute those
Proof of concept:
$var = "Before";
function getVar(){
global $var;
return $var;
}
$array = Array(
"variable" => create_function(null, "return 'Var = ' . getVar();")
);
$var = "After";
echo $array['variable']();
returns
Var = After

Related

PHP's assignment by reference is not working as expected

Why the following
class AClass
{
public function __construct ()
{
$this->prop = "Hello";
}
public function &get ()
{
return $this->prop;
}
protected $prop;
}
function func (&$ref)
{
$ref = &$ref->get();
}
$value = new AClass();
func($value);
var_dump( $value );
outputs
object(AClass)#2 (1) {
["prop":protected]=>
string(5) "Hello"
}
Shouldn't the $value variable become a reference to $prop and be of type string instead of staying of type AClass?
http://ideone.com/g1hTNV
Consider this piece of code (It's the same as your code, just without everything else):
$value = new stdClass;
$ref = &$value;
$var = "Hello";
$ref = &$var; // this is where you write $ref = &$ref->get();
var_dump($value);
This gives as expected an empty object and not string(5) Hello.
Why?
We're in line 4 overwriting the reference to $value with a reference to $var.
$ref now holds a reference to $var; the value of $value remains unaffected.
What we're not doing
We don't assign the value of $var to $value.
We don't assign to $value a reference to $var.
Conclusion
Assigning references to a variable via another referencing variable is just not possible in PHP.
bwoebi is totally right about how PHP references work. Without a dereference operator it would become impossible to know exactly what you mean when using pointers, so PHP has used another approach. This does not, however, mean that what you want is impossible, you just can't do it all inside a function:
class AClass
{
public function __construct ()
{
$this->prop = "Hello";
}
public function &get()
{
return $this->prop;
}
public $prop;
}
function &func($ref)
{
return $ref->get();
}
$root = new AClass();
$value = &func( $root );
var_dump( $value );
// string(5) "Hello"
$value = "World";
var_dump( $root->get() );
// string(5) "World"
http://codepad.org/gU6pfzUO
You should remove the ampersand in your func function. Then it will return you the string.
function func (&$ref)
{
$ref = $ref->get();
}
what you want can be acheived by this-
<?php
class AClass
{
public function __construct ()
{
$this->prop = "Hello";
}
public function &get ()
{
return $this->prop;
}
protected $prop;
}
function func (&$ref)
{
$ref= $ref->get();
}
$value = new AClass();
func($value);
print_r( $value );
?>
class AClass
{
public function __construct ()
{
$this->prop = "Hello";
}
public function &get ()
{
return $this->prop;
}
protected $prop;
}
function func (&$ref)
{
$ref = $ref->get(); // You don't need the ampersand here
}
$value = new AClass();
func($value);
var_dump( $value ); // outputs: string(5) "Hello"
Just change protected into public for the sake of testing.
$value = new AClass();
$myValue = &$value->get();
var_dump($myValue );
var_dump($value->prop);
$value->prop = 'test';
var_dump($value->prop);
var_dump($myValue );
Output :
string 'Hello' (length=5)
string 'Hello' (length=5)
string 'test' (length=4)
string 'test' (length=4)
incase you think that function is necessary you can use global variable.
Your function func() needs to return a value and then it needs to assign to a variable what func() returned. See modified code below:
function func (&$ref) {
$ref = &$ref->get();
return $ref;
}
$value = new AClass();
$new_value = func($value);
var_dump( $new_value );

Anonymous functions in a class

is there a better way to call an anonymous function inside a class? Here is a simple example that clearifies what I mean.
class foo
{
private $call_back_1 = null;
private $call_back_2 = null;
function __construct($func1, $func2)
{
$this->call_back_1 = func1;
$this->call_back_2 = func2;
}
function provokeCallBacks()
{
//this does not work, and gives an error
$this->call_back_1();
//I would like to avoid this
$method = $this->call_back_2;
$method();
}
}
$call1 = function(){ echo "inside call 1"};
$call2 = function(){ echo "inside call 2"};
$test = new foo(call1, call2);
$test->provokeCallBacks();
* Update 1: Please ignore any syntax error as I have written this on the fly for demo puposes. *
Inside foo:provokeCallBacks, I am trying to call the anonymous functions how ever the first way does not works and gives an error. The second one works but it's a bit stupid that I have to use a temp variable called "$method" to make the call.
I want to know if there exists a better way to call the anonymous function.
call_user_func($this->call_back_1);
No, it's not possible to call an anonymous function via $this.
Another options is;
call_user_func($this->call_back_1);
Being PHP loosely typed, it can't do like {$this -> callback}(); you have to store it in a temp variable or to use call_user_func() either.
EDIT - consider something like this:
class Lambdas
{
protected $double;
protected $triple;
public function __construct($double, $triple)
{
$this -> double = $double;
$this -> triple = $triple;
}
public function __call($name, $arguments)
{
if( is_callable($this -> {$name}) ){
return call_user_func_array($this -> {$name}, $arguments);
}
}
}
$lambdas = new Lambdas(
function($a){ return $a * 2;},
function($a){ return $a * 3;}
);
echo $lambdas -> double(2); // prints 4
echo $lambdas -> triple(2); // prints 6
Dirty and dangerous, but you might succeed using eval..
class foo
{
private $call_back_1 = null;
private $call_back_2 = null;
function __construct($func1, $func2)
{
$this->call_back_1 = func1;
$this->call_back_2 = func2;
}
function provokeCallBacks()
{
eval($this->call_back_1);
eval($this->call_back_2);
}
}
call1 = 'echo "inside call 1"';
call2 = 'echo "inside call 2"';
$test = foo(call1, call2);
$test->provokeCallBacks();
I know your question has been answered but you can try changing your approch ..
class Foo {
private $calls = array();
function __set($key, $value) {
$this->calls[$key] = $value;
}
function __call($name, $arg) {
if (array_key_exists($name, $this->calls)) {
$this->calls[$name]();
}
}
function __all() {
foreach ( $this->calls as $call ) {
$call();
}
}
}
$test = new Foo();
$test->A = function () {
echo "inside call 1";
};
$test->B = function () {
echo "inside call 2";
};
$test->A(); // inside call 1
$test->B(); // inside call 2
$test->__all(); // inside call 1 & inside call 2

get a list of all variables defined outside a class by user

i have something like this:
class foo
{
//code
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
i can get in class foo a list of all variables defined outside by user (newVariable, otherVariable,etc)? Like this:
class foo
{
public function getUserDefined()
{
// code
}
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
var_dump($var->getUserDefined()); // returns array ("newVariable","otherVariable");
Thanks!.
Yes, using get_object_vars() and get_class_vars():
class A {
var $hello = 'world';
}
$a = new A();
$a->another = 'variable';
echo var_dump(get_object_vars($a));
echo '<hr />';
// Then, you can strip off default properties using get_class_vars('A');
$b = get_object_vars($a);
$c = get_class_vars('A');
foreach ($b as $key => $value) {
if (!array_key_exists($key,$c)) echo $key . ' => ' . $value . '<br />';
}
What is your goal? Imo it's not very good practice (unless you really know what you are doing). Maybe it's good idea consider create some class property like "$parameters" and then create setter and getter for this and use it in this way:
class foo {
private $variables;
public function addVariable($key, $value) {
$this->variables[$key] = $value;
}
public function getVariable($key) {
return $this->variables[$key];
}
public function hasVariable($key) {
return isset($this->variables[$key]);
}
(...)
}
$var = new foo();
$var->addVariable('newVariable', 1);
$var->addVariable('otherVariable', "hello, im a variable");
And then you can use it whatever you want, for example get defined variable:
$var->getVariable('otherVariable');
To check if some var is already defined:
$var->hasVariable('someVariable')
get_class_vars() http://php.net/manual/en/function.get-class-vars.php
You question is not clear though.
$var->newVariable = 1;
there are two possible contex of above expression
1) you are accessing class public variables.
like
class foo
{
public $foo;
public function method()
{
//code
}
}
$obj_foo = new foo();
$obj_foo->foo = 'class variable';
OR
2) you are defining class variable runtime using _get and _set
class foo
{
public $foo;
public $array = array();
public function method()
{
//code
}
public function __get()
{
//some code
}
public function __set()
{
// some code
}
}
$obj_foo = new foo();
$obj_foo->bar= 'define class variable outside the class';
so in which context your question is talking about?

Access variable defined in other file from class

I would like to know if there is a way to access a variable defined in an other file from a class in PHP.
Example :
file_01.php
<?php
$a = 42;
?>
file_02.php
<?php
require_once('file_01.php');
class mnyClass
{
private $myVar;
function __construct($var = $a)
{
$this->myVar = $var;
}
function getVar()
{
return $this->var;
}
function setVar($var)
{
$this->myVar = $var;
}
}
?>
Obviously, my class is more complicated. I have chosen this example for a better comprehension of what I try to do ;)
Thank you in advance.
You cannot do this:
function __construct($var = $a)
{
$this->myVar = $var;
}
What you can do is pass it:
<?php
require_once('file_01.php');
$mnyClass = new mnyClass($a);// the torch has been passed!
class mnyClass
{
private $myVar;
function __construct($var = null)
{
$this->myVar = $var;
}
function getVar()
{
return $this->var;
}
function setVar($var)
{
$this->myVar = $var;
}
}
?>
OR you can do this (it is not advisable):
function __construct($var = null)
{
if($var === null) $var = $GLOBALS['a']; //use global $a variable
$this->myVar = $var;
}
You could access the variable via GLOBALS:
http://php.net/manual/en/language.variables.scope.php
EDIT: a little more detail-
function __construct() {
$this->myVar = $GLOBALS['a'];
}
It sounds like you're setting up some application defaults. It might make sense to define these as constants:
file_01.php:
define('DEFAULT_VALUE_FOR_A', 42);
file_02.php
class myClass
{
function __construct($var = DEFAULT_VALUE_FOR_A) {
}
}
Finally, I use this method :
<?php
require_once('file_01.php');
class myClass {
private $myVar;
function __construct($var = NULL)
{
global $a;
if($var == NULL)
$this->myVar = $a;
else
$this->myVar = $var;
}
}
?>
I declare my variable $a as global in the constructor, set the default value of my $var to NULL and check if the constructor was called with parameter(s) ($var == NULL).

php bind variable to function's scope in older PHP

I would like to bind a variable to a function's scope, I can do this in php use the 'use' keyword after PHP 5.3, however how do I do the equivalent in versions < PHP 5.3?
test_use_keyword();
function test_use_keyword(){
$test =2;
$res=array_map(
function($el) use ($test){
return $el * $test;
},
array(3)
);
print_r($res);
}
You can use a global variable, but you should always avoid globals variables whereever possible. As a suggestion, without knowing, what you are trying to solve with this
class Xy ( {
private $test;
public function __construct ($test) {
$this->test = $test;
}
public function call ($el) {
return $el * $this->test;
}
}
print_r(array_map(array(new Xy(2), 'call'), array(3));
Also possible are the good old lambdas
$test = 2;
$a = create_function ('$el', 'return $el * ' . $test . ';');
print_r (array_map($a, array(3)));
Normally through globals, seriously. Although hacks could be used to mimic the functionality, like partial functions in php. Extracted from article:
function partial()
{
if(!class_exists('partial'))
{
class partial{
var $values = array();
var $func;
function partial($func, $args)
{
$this->values = $args;
$this->func = $func;
}
function method()
{
$args = func_get_args();
return call_user_func_array($this->func, array_merge($args, $this->values));
}
}
}
//assume $0 is funcname, $1-$x is partial values
$args = func_get_args();
$func = $args[0];
$p = new partial($func, array_slice($args,1));
return array($p, 'method');
}
And only after that could you have something like.
function multiply_by($base, $value) {
return $base * $value;
}
// ...
$res = array_map(partial("multiply_by", $test), array(3));
Not... worth... it.

Categories