This code works but $vars can't be defined in the call() function.
Why do $vars can't be passed to the array_walk_recursive()?
class lib{
private $library;
function __construct($lib="")
{
$this->library = $lib;
}
function set($vars)
{
$decoded_classes = json_decode($this->library,true);
array_walk_recursive($decoded_classes,function(&$f) {$f = create_function($vars,$f);});
return $decoded_classes;
}
}
$json = '
{
"class1": {
"function1":"return \"$a<b>$b</b>!\";"
},
"class2": {
"function2":"return $b;",
"function3":"return $c;"
},
"function1":"return \"test\";"
}';
$lib = new lib($json);
$lib = $lib->set("$a,$b");
$lib = $lib["class1"]["function1"]("asdasasd","asdasasd");
echo $lib;
Firstly, have a look at this example with variable scoping for closures. You need to pass the variable in with the use keyword, eg:
array_walk_recursive($decoded_classes,function(&$f) use ($vars) {$f = create_function($vars,$f);});
It would be good if you defined $a, $b, etc for us, so we could actually test your code.
Related
I have some trouble,When I define a static variable in a method and call it multiple times, the code is as follows:
function test()
{
static $object;
if (is_null($object)) {
$object = new stdClass();
}
return $object;
}
var_dump(test());
echo '<hr>';
var_dump(test());
The output is as follows:
object(stdClass)[1]
object(stdClass)[1]
Yes, they return the same object.
However, when I define a closure structure, it returns not the same object.
function test($global)
{
return function ($param) use ($global) {
//echo $param;
//exit;
static $object;
if (is_null($object)) {
$object = new stdClass();
}
return $object;
};
}
$global = '';
$closure = test($global);
$firstCall = $closure(1);
$closure = test($global);
$secondCall = $closure(2);
var_dump($firstCall);
echo '<hr>';
var_dump($secondCall);
The output is as follows:
object(stdClass)[2]
object(stdClass)[4]
which is why, I did not understand.
By calling test(...) twice in your sample code, you have generated two distinct (but similar) closures. They are not the same closure.
This becomes more obvious some some subtle improvements to your variable names
$closureA = test($global);
$firstCall = $closureA(1);
$closureB = test($global);
$secondCall = $closureB(2);
var_dump($firstCall, $secondCall);
Now consider this code alternative:
$closureA = test($global);
$firstCall = $closureA(1);
$secondCall = $closureA(2);
var_dump($firstCall, $secondCall);
Does that help you understand?
I'm trying to call some "global/static" variables($agent, $version) inside a class but I don't know how to insert them in the class itself . Basically I declare the class "$myclass = new myClass($agent, $version) but I don't know how to call these variables inside the class (e.g. use them in the getProducts function ). I know the questions sounds stupid but I just don't get it .
index.php :
$myclass = new myClass($agent, $version);
$agent = "firefox";
$version = "234";
$catalog = $myClass->$getProducts("http://amazon.com", "red");
myclass.class.php :
class myClass {
function getXML ($agent, $version) {
//do something
return $
}
function getProducts ($url, $color) {
$product = $this->getXML($agent, $version);
$catalog = str_replace("asus", "", $product);
return $catalog
}
}
It doesn't sound like static variables are what you're looking for and are best avoided unless you know what you're doing (they're not really object oriented and not needed at all in PHP 5.3+). From the code that you've provided it looks like your expecting to pass the arguments into the object instantiation (new), so you should create a constructor for the class that accepts the arguments and assigns them to instance variables to be used in the method.
You can declare them using the static keyword.
From http://php.net/manual/en/language.oop5.static.php :
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
}
print Foo::$my_static . "\n";
I suppose that you do not mean "static" variables but "properties":
class myClass {
// Declare the properties
private $agent, $version;
public function __construct($agent, $version) {
// Copy the arguments to the class members
$this->agent = $agent;
$this->version = $version;
}
public function getProducts($url, $color) {
$product = $this->getXML();
// ...
}
private function getXML() {
// Use the values stored in $this->agent etc.
$agent = $this->agent;
// ...
}
}
Usage:
$agent = "firefox";
$version = "234";
$instance = new myClass($agent, $version);
$catalog = $instance->getProducts("http://amazon.com", "red");
This is also wrong:
function getProducts ($url, $color){
$product = $this->getXML($agent, $version);
$catalog = str_replace("asus", "", $product);
return $catalog
}
You cant pass $agent and $version variables in the getXML method unless you dont either, construct them first, or pass them in your getProducts method.
I am trying to create an anonymous function but need to access variables from the current scope in it's definition:
class test {
private $types = array('css' => array('folder' => 'css'));
public function __construct(){
//define our asset types
foreach($this->types as $name => $attrs){
$this->{$name} = function($file = ''){
//this line is where is falls over!
//undefined variable $attrs!
return '<link href="'.$attrs['folder'].'/'.$file.'" />';
}
}
}
}
$assets = new test();
Obviously this example is very very minimalistic but it gets across what I am trying to do.
So, my question is,
How can I access the parent scope only for the definition of the function?
(once defined I obviously don't need that context when the function is called).
Edit #1
Ok so after using Matthew's answer I have added use as below; but now my issue is that when I call the function I get no output.
If i add a die('called') in the function then that is produced, but not if I echo or return something.
class test {
private $types = array('css' => array('folder' => 'css'));
public function __construct(){
//define our asset types
foreach($this->types as $name => $attrs){
$this->{$name} = function($file = '') use ($attrs){
//this line is where is falls over!
//undefined variable $attrs!
return '<link href="'.$attrs['folder'].'/'.$file.'" />';
}
}
}
public function __call($method, $args)
{
if (isset($this->$method) === true) {
$func = $this->$method;
//tried with and without "return"
return $func($args);
}
}
}
$assets = new test();
echo 'output: '.$assets->css('lol.css');
function($file = '') use ($attrs)
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.
I'm trying to reference a private variable of an object from within a closure. The code below would seem to work, but it complains Fatal error: Cannot access self:: when no class scope is active in test.php on line 12 and Fatal error: Using $this when not in object context in test.php on line 20.
Any ideas how to accomplish the same results using a closure while keeping the variables private and without making helper functions (defeating the whole idea of a private variable).
class MyClass
{
static private $_var1;
private $_var2;
static function setVar1( $value )
{
$closure = function () use ( $value ) {
self::$_var1 = $value;
};
$closure();
}
function setVar2( $value )
{
$closure = function () use ( $value ) {
$this->_var2 = $value;
};
$closure();
}
}
MyClass::setVar1( "hello" ); //doesn't work
$myclass = new MyClass;
$myclass->setVar2( "hello" ); //doesn't work
Edit to note, this answer was originally meant for PHP5.3 and earlier, it's possible now. For current information, see this answer.
This is not directly possible. In particularly, closures have no associated scope, so they cannot access private and protected members.
You can, however, use references:
<?php
class MyClass
{
static private $_var1;
private $_var2;
static function setVar1( $value )
{
$field =& self::$_var1;
$closure = function () use ( $value, &$field ) {
$field = $value;
};
$closure();
}
function setVar2( $value )
{
$field =& $this->_var2;
$closure = function () use ( $value, &$field ) {
$field = $value;
};
$closure();
}
}
MyClass::setVar1( "hello" );
$myclass = new MyClass;
$myclass->setVar2( "hello" );
This is possible starting in PHP 5.4.0
class test {
function testMe() {
$test = new test;
$func = function() use ($test) {
$test->findMe(); // Can see protected method
$test::findMeStatically(); // Can see static protected method
};
$func();
return $func;
}
protected function findMe() {
echo " [find Me] \n";
}
protected static function findMeStatically() {
echo " [find Me Statically] \n";
}
}
$test = new test;
$func = $test->testMe();
$func(); // Can call from another context as long as
// the closure was created in the proper context.
Closures have no concept of $this or self -- they are not tied to objects in that way. This means that you would have to pass the variables through the use clause... something like:
$_var1 =& self::$_var1;
$closure = function() use ($value, &$_var1) {
$_var1 = $value;
};
$_var2 =& $this->_var2;
$closure = function() use ($value, &$_var2) {
$_var2 = $value;
};
I haven't tested the above code, but I believe it to be correct.