How to replace a function with unknown argument names? - php

This is what I want to do:
$var = "foo";
$unknown = "";
function do($arg1, $arg2) {
$arg2 = "bar";
magic($arg2);
}
do($var, $unknown);
echo $unknown;
This should return: bar
I know that this would work if I'd define my function like this:
function do($arg1, $unknown) {
global $unknown;
$unknown = "bar";
}
As you probably guessed already, the variable name of $unknown is unknown.
I need this because I'm writing a PHP sandbox using apd. I want to replace exec($cmd, $ret) in a PHP script I don't known with my own function.
So if the unknown PHP script looks like this:
$foo = "";
exec('whois google.com', $foo);
echo $foo;
I'll have a problem replacing exec with my own function do() emulating the same functionality.

You want to pass the parameter by reference:
$var = "foo";
$unknown = "";
function foo($arg1, &$arg2) { // NOTE EXTRA "&"
$arg2 = "bar";
}
foo($var, $unknown);
echo $unknown;
See it in action.

Related

PHP - Make 'new' of a Class and Arguments set in a string

I've a Class and Arguments set in a variable like this:
$myVar = '\Api\MyClass(\DateTimeInterface::RFC3339_EXTENDED)';
I need to make a new of this variable.
I tried multiple solutions and at the end the new of the Class was solved but I cannot pass the argument.
My code is:
<?php
$myVar = '\Api\MyClass(\DateTimeInterface::RFC3339_EXTENDED)';
$className = substr($myVar, 0, strpos($myVar, "(")); // $className will be: \Api\MyClass
if (class_exists($className)) {
preg_match('/\((.*?)\)/', $myVar, $classArguments); $classArguments will be: \DateTimeInterface::RFC3339_EXTENDED
$obj = new $className($classArguments[1]); // it doesn't work
}
the problem is that $classArguments[1] is passed as string to my class. Below the difference:
// It works
$p = \DateTimeInterface::RFC3339_EXTENDED;
var_dump($p);
// and return
string(15) "Y-m-d\TH:i:s.vP"
// It doesn't work
$p = "\DateTimeInterface::RFC3339_EXTENDED";
var_dump($p);
// return
string(36) "\DateTimeInterface::RFC3339_EXTENDED"
can you help me?
Thank you.
New can only be used to create an instance. Make your constructor expecting that date format as default, so you are not required to pass it.
class MyClass {
public function __construct(string $dateFormat = DateTimeInterface::RFC3339_EXTENDED)
{
}
}
$var = 'MyClass';
$instance = new $var;
$p = "\DateTimeInterface::RFC3339_EXTENDED";
will not work, because that is now a string and not the constants value.
You also can pass something like so
class MyClass {
public function __construct(string $something = '')
{
echo $something;
}
}
$var = 'MyClass';
$text = 'Hello world';
$instance = new $var($text);
Hello world
If you need the complete string to be parsed try eval(), but not recommended.
$var = 'new MyClass("hello world");';
$instance = eval($var);
Hello world
or, but not recommended.
$var = 'MyClass("hello world")';
$instance = eval("new {$var};");
Hello world
You can use the constant function to get the value of a constant.
A simple example class that just outputs the parameter value when initialized.
class MyClass
{
function __construct($arg) {
echo "$arg\n";
}
}
new MyClass('anything'); // outputs "anything"
This is just a helper that gets the class name and argument string from a string like your $myVar.
function parseClassAndArgument(string $str): array {
preg_match('/(.*)\((.*)\)/', $str, $matches);
[, $className, $argument] = $matches;
return [$className, $argument];
}
This helper allows you to pass either a string value or a name of a constant, and guesses which one it is based on whether there is a :: in the string name. You can replace this with just the constant($argument) part if you know $myVar will always contain a constant name.
function parseArgValue(string $argument): string {
return strpos($argument, '::') ? constant($argument) : $argument;
}
This recognizes that $argument refers to a constant and outputs Y-m-d\TH:i:s.vP
$myVar = 'MyClass(\DateTimeInterface::RFC3339_EXTENDED)';
[$className, $argument] = parseClassAndArgument($myVar);
new $className(parseArgValue($argument));
This outputs the string foo as is.
$myVar = 'MyClass(foo)';
[$className, $argument] = parseClassAndArgument($myVar);
new $className(parseArgValue($argument));
This is a simplified example that only handles one parameter for the class constructor, but I hope it helps to get you along!

PHP equivalent to [&, epsilon] C++ "Capturing" variables in lambda?

Is there a way I can pass any variable currently in scope by reference to a lambda function without listing them all in the use(...) statement?
Something like
$foo = 12;
$bar = 'hello';
$run = function() use (&) {
$foo = 13;
$bar = 'bye';
}
// execute $run function
Resulting in $foo equal to 13 and $bar equal to 'bye'.
TL;DR The short answer is no. You need to name the variables
You don't need closure variables for this. It's not even valid to use use with named functions since it won't have a nested lexical scope. Use the global keyword to make the variables "dynamic". You have to name all the variables that are special.
$foo = 12;
$bar = 'hello';
function run() {
global $foo,$bar;
$foo = 13;
$bar = 'bye';
}
run();
print "$foo, $bar\n"; // prints "13, bye"
For a lexical anonymous functions you need to name all variables with the use keyword and use & to get it referenced:
$foo = 12;
$bar = 'hello';
$run = function () use (&$foo,&$bar) {
$foo = 13;
$bar = 'bye';
};
call_user_func($run);
print "$foo, $bar\n"; // prints "13, bye"
You could use get_defined_vars() along with extract():
$foo = 12;
$bar = 'hello';
$vars = get_defined_vars();
foreach (array_keys($vars) as $var) {
$vars[$var] = &$$var; // keep refs of all variables from current scope
}
$run = function() use($vars) {
extract($vars, EXTR_REFS);
$foo = 13;
$bar = 'bye';
};
// execute $run function
$run();
print $foo; // prints 13
print $bar; // prints bye

change and initialise variables in a function

I was wondering if it's possible to change and initialize variables in a function without passing arguments to the function. Here is what I want to achieve:
$foo = 'Lorem';
$array = array();
foobar($foo);
function foobar(){
if (strlen($foo)== 1)
$bar = 'Ipsum';
else
$array[] = 'error';
}
fubar();
function fubar(){
if (empty($fouten))
echo $bar;
}
$foo is a local (uninitialized) variable inside a function. It is different from the global variable $foo ($GLOBALS['foo']).
You have two ways:
$foo;
$bar;
$array = array();
function foobar(){
global $foo, $array, $bar;
if (strlen($foo)== 1)
$bar = 'Ipsum';
else
$array[] = 'error';
}
or by using the $GLOBAL array …
This is not really good practice though and will become a maintenance nightmare with all those side effects
Functions in php can be given arguments that have default values. The code you posted as written will give you notices for undefined variables. Instead, you could write:
function foobar($foo = null) {
if($foo) { // a value was passed in for $foo
}
else { // foo is null, no value provided
}
}
Using this function, neither of the below lines will produce a notice
foobar();
foobar('test');

Access local variable in function from outside function (PHP)

Is there a way to achieve the following in PHP, or is it simply not allowed? (See commented line below)
function outside() {
$variable = 'some value';
inside();
}
function inside() {
// is it possible to access $variable here without passing it as an argument?
}
note that using the global keyword is not advisable, as you have no control (you never know where else in your app the variable is used and altered). but if you are using classes, it'll make things a lot easier!
class myClass {
var $myVar = 'some value';
function inside() {
$this->myVar = 'anothervalue';
$this->outside(); // echoes 'anothervalue'
}
function outside() {
echo $this->myVar; // anothervalue
}
}
Its not possible. If $variable is a global variable you could have access it by global keyword. But this is in a function. So you can not access it.
It can be achieved by setting a global variable by$GLOBALS array though. But again, you are utilizing the global context.
function outside() {
$GLOBALS['variable'] = 'some value';
inside();
}
function inside() {
global $variable;
echo $variable;
}
No, you cannot access the local variable of a function from another function, without passing it as an argument.
You can use global variables for this, but then the variable wouldn't remain local.
It's not possible. You can do it by using global. if you just only do not want to define the parameters but could give it inside the function you can use:
function outside() {
$variable = 'some value';
inside(1,2,3);
}
function inside() {
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
}
}
for that see the php manual funct_get_args()
You cannot access the local variable in function. Variable have to set as global
function outside() {
global $variable;
$variable = 'some value';
inside();
}
function inside() {
global $variable;
echo $variable;
}
This works

php convert string to method call

<?php
$str = "getList";
//now by doing something to $str i need to call getList() method any sugesstions
function getList(){
echo "get list called";
}
?>
Use the call_user_func() function to call the function by name.
This feature is known as Variable functions, here is an example from php.net:
<?php
function foo() {
echo "In foo()<br />\n";
}
function bar($arg = '')
{
echo "In bar(); argument was '$arg'.<br />\n";
}
// This is a wrapper function around echo
function echoit($string)
{
echo $string;
}
$func = 'foo';
$func(); // This calls foo()
$func = 'bar';
$func('test'); // This calls bar()
$func = 'echoit';
$func('test'); // This calls echoit()
?>
More Info:
http://php.net/manual/en/functions.variable-functions.php
You can use the variable as a function name. This will execute getList():
$str();
However, stuff like this is mostly a symptom of a design problem. Care to elaborate what you need this for?

Categories