Pass Dynamic Values from one function to another function in class - php

Hi all i have a function in a class which will print all the variable pass for this function
Class Code :
<?php
class MyPrintClass {
public function printVaraible() {
var_dump(func_get_args())
}
}
$printVar = new MyPrintClass;
?>
if i use like below its correctly working and printing all the values pass.
$print->printVaraible('value1','Value2',20);
The output i got for above cmd
array (size=1)
0 => string 'value1' (length=6)
1 => string 'value2' (length=6)
2 => string 'value3' (length=6)
if i use like blow its showing as a single array.. i want the value seperated.. how its possible ?
function getVal(){
global $printVar;
$print->printVaraible(func_get_args());
}
I need to pass the value like below
getVal('value1','Value2',20);
and i need the output as
array (size=1)
0 => string 'value1' (length=6)
1 => string 'value2' (length=6)
2 => string 'value3' (length=6)
Currently i get NULL as the output
Updated Question Based On the Answer Given By deceze
** I Also had a small change in my code**
Class Code :
<?php
class MyPrintClass {
public function printVaraible($tag,$value) {
echo $tag.' == '.$value;
var_dump(func_get_args());
}
}
$printVar = new MyPrintClass;
?>
Converted Class To Function By
<?php
function getVal($tag,$value) {
global $printVar;
call_user_func_array([$printVar, 'printVariable'], $tag,$value,func_get_args());
}
?>
If i try to use it as below i get error
<?php getVal('first','second','third,'fourth'); ?>
Warning: call_user_func_array() expects exactly 2 parameters, 4 given

call_user_func_array([$print, 'printVariable'], func_get_args());
This calls the function with separate parameters from an array. I'd question the usefulness of this though, since you'll just end up with an array from func_get_args anyway. Why not pass arrays around in the first place?

Your getting null in the return because you never return anything, from the functions above.
if you want to call a class method I suggest you look into Refection or you can also do
$a = 'printVaraible';
$class->$a(1,3); //
besides using call_user_func_array, I would also suggest looking into closures (php > 5.3 ), which will let you write them this way.
$a = function foo(){ echo 'foo'};
$a();
Last thing I would generally avoid using global, as it obscures in your code where the values come from. It is always better to inject values into the function scope and not mix that with the global, imaging hunting that global down in a large project, I just avoid them at all cost and forget they exist.

Related

PHP Attempting to invoke a serialized / encoded anonymous function within a class method returns 'Method name must be a string'

I have a class within which I want to
Set an array
Loop through the array
Invoke anonymous functions set in #1 as I loop through the array in #2
EDIT: The code below is working when tested out of my application, but in my CodeIgniter 3 Controller, I keep getting an error: Method name must be a string
My simplified code for the purposes of example (CodeIgniter 3):
<?php
class MyClass {
// Setting my array
public function my_arr ($options = array())
{
$arr = array(
'1' => array(
'a' => 'z',
'b' => function($i) {
return 'c' . $i;
},
),
'2' => array(
'a' => 'y',
'b' => function($i) {
return 'd' . $i;
},
),
);
return $arr;
/**
*
* EDIT: Later in my code I found that there was some kind
* of serialization/encoding attempt like:
* json_decode(json_encode($arr));
*/
}
// Doing My Loop
public function do_loop()
{
$my_arr = $this->my_arr();
$i = 0;
foreach($my_arr as $key => $value){
$anonymous_function = $value['b'];
echo $anonymous_function($i) . '<br>'; // Keep getting `Method name must be a string`
$i++;
}
}
}
(new MyClass())->do_loop();
Posting back here in hopes that it helps.
My issue:
Later on in my codebase, I was trying to encode/serialize my method's
output.
After a bit of reading, I found out that json_encode() &
serialize() don't support serialization of closures / anonymous functions.
So, the Method name must be a string error happend because my attempts to encode/serialize - effectively - stripped the anonymous functions out & thus referenced a null function.
How I resolved the issue:
First I started with Opis Closure library to seralize the closure (I didn't end up going with this, but including it because I think it's a pretty cool library)
After the above, I just realized that I should refactor so that I wasn't trying serialize closures at all.

Extracting array as list of arguments passed to function

Is it possible to make something like that:
$array = array('id' => '5', 'something_else' => 'hi');
function some_function($id, $something_else)
{
echo $something_else;
}
some_function(extract($array));
This code is giving me true/false and not $id,$something_else, etc..
It is important for me to do something like that, because I have different list of variables for each function ( I'm working on my ( let's call it ) "framework" and I want to pass list of variables instead of array with variables. This code is actually going in my router so it's not quite that simple, but in the end it comes to that ).
I assume you know how your array is built. So, why do not you just pass an array as a parameter and then use it in your function ?
If you do something like this you can access to your array's values :
echo $array['something_else'];
And build your function like this :
$array = array('id' => '5', 'something_else' => 'hi');
function some_function($an_array)
{
echo $an_array['something_else']; // value for something_else
}
some_function($array);
Or if you don't want to change function's parameters, call it like this :
some_function($array['id'], $array['something_else']);

Message: Attempt to increment/decrement property of non-object

$order_temp = $this->mdl_admin->get_latest_order_id($_POST['parent_id']);
if ($order_temp) {
$order = (string)$order_temp->order++;
var_dump($order);
die();
}
This code above produce this error:
Message: Attempt to increment/decrement property of non-object
And the vardump is string '' (length=0)
If I do just something like this to vardump the variable:
$order_temp = $this->mdl_admin->get_latest_order_id($_POST['parent_id']);
if ($order_temp) {
var_dump($order_temp);
die();
}
the output is :
array (size=1)
0 =>
object(stdClass)[28]
public 'id' => string '16' (length=2)
public 'name' => string 'sssssssssssssss' (length=15)
public 'slug' => string 'aaaaaaaaa' (length=9)
public 'title' => string 'aaaaaa' (length=6)
public 'body' => string '<p>asdas asd asd </p>' (length=21)
public 'order' => string '1' (length=1)
public 'parent_id' => string '5' (length=1)
I just want to add 1 to the $order_temp->order so if e.g. the $order_temp->order = 2 the result $order = 3.
What am I doing wrong?
$order_temp is not an object, as the error message says. When you try to access (or in this case, increment) a property of something that isn't an object (and so does not have properties), you get this error.
Not knowing what $this->mdl_admin->get_latest_order_id does, I can only go so far, BUT, I can tell you to use explicit comparisons in if statements, and that your type coercion isn't doing what you expect.
Use explicit comparison:
if (is_object($order_temp) === true)
.. that might not be the cause of your bug, but that's good practice.
Your use of ((string)) in assignment coerces the presumed object variable to a string, which you then try to access property of. This is not the droid you are looking for. It appears, from PHP's perspective, that you want to do this:
"0"->order++;
...which doesn't make sense.
PHP uses type juggling[doc]. Whether your object's property order started out as a string or not, as soon as you use the increment operator ++, PHP juggles the type to become an integer. If you want a string, all you have to do is start treating it like a string:
$order_temp->order++; // <-- variable is an integer, $order_temp->order === 1
$order_temp->order .= " and bob's your uncle"; // <-- variable is a string, $order_temp->order === "1 and bob's your uncle"
For that reason, type coercion is seldom necessary in PHP.
Finally, you can do this exactly in the way that you're trying, but you'll have to understand the way the increment ++ operator works.
$number = 0;
$output = $number++;
echo "Output: ".$output; // Output: 0
$number = 0;
$output = ++$number;
echo "Output: ".$output; // Output: 1
... by placing the increment operator at the FRONT of the assignment, the return will be the incremented variable after the increment operation. If you put the operator at the end, then the return is the variable before the increment operation.
That means you could do this:
$order_number_as_string = (string) (++$one_order->order);
By enclosing the increment operator in parenthesis and type casting the outside, plus putting the increment operator as a prefix, you will get the expected results.
Documentation
Increment/Decrement operators - http://php.net/manual/en/language.operators.increment.php
Type juggling - http://php.net/manual/en/language.types.type-juggling.php
settype - http://php.net/manual/en/function.settype.php
<?php
class Test
{
public $order = 10;
}
$order_temp = new Test();
$order = (string)$order_temp->order++;
var_dump($order);
//string(2) "10"
$order = (string)$order_temp->order;
var_dump($order);
//string(2) "11"
?>
Your $order_temp is not an object. So that is what is causing the problems. Also note that you might not get the expected results, even if it works.
Your $order will contain the OLD value. See my test.
UPDATE
The var_dump of your $order_temp shows that its an array. You could use
$order_temp[0]->order++;
$order = $order_temp[0]->order
var_dump($order);

Parsing Classes, Functions and Arguments in PHP

I want to create a function which receives a single argument that holds the path to a PHP file and then parses the given file and returns something like this:
class NameOfTheClass
function Method1($arg1, $arg2, $arg2)
private function Method2($arg1, $arg2, $arg2)
public function Method2($arg1, $arg2, $arg2)
abstract class AnotherClass
function Method1($arg1, $arg2, $arg2)
private function Method2($arg1, $arg2, $arg2)
public function Method2($arg1, $arg2, $arg2)
function SomeFunction($arg1, $arg2, $arg3)
This function should return all the classes, methods and function that exist in the given file with all the defined identifiers (abstract, public, private, protected, static, extends, interfaces, ...).
My first tought was to use regular expressions to do this, however these behave quite badly with comments, ie: /* this function returns(max(salary)) */ and become quite complex if I want to properly support scopes.
Another possible solution was to use the following built-in PHP functions:
get_declared_classes
get_declared_interfaces
get_defined_functions
get_class_methods
However these functions don't allow me to see the file where the classes / methods / functions are defined and thus it's not very useful.
I believe the Tokenizer extension is the solution for my problem, however I have never used this extension before.
If you are using PHP 5, the Reflection API is your tool.
Example:
$class = new ReflectionClass("NameOfTheClass");
$methods = $class->getMethods();
foreach($methods as $m) {
print $m->name;
$m->isPrivate() ? print "Private" : print "";
$m->isPublic() ? print "Public" : print "";
$params = $m->getParameters();
foreach($params as $p) {
print $p->getName();
}
}
I suggest the following procedure:
store the current output of get_declared_classes, get_declared_interfaces and get_defined_functions(if you really need to support them)
include the file
compare get_declared_classes, get_declared_interfaces and get_defined_functions with the ones you stored to see what's new
use reflection to analyze them
goto step 2 for the next file
Like you found out yourself, regex are quite not the right tool for the job, here ^^
And, like you said, the built-in functions you proposed are not that helpful either -- only thing that might be helpful is that they allow you to know which class exists... But they'll return builtin classes too :-(
Using the Tokenizer extension seems a bit overkill/hard to me ; I would probably not go that way, actually : too "low-level", I suppose.
Instead, I would take a look at PHP's Reflection API : it exists exactly to reverse-engineer classes, interfaces, functions, ...
So, I suppose it would be quite well-suited for what you are trying to do.
Edit : here is a quick example :
First, let's try to do reflection on a class :
include dirname(__FILE__) . '/temp-2.php';
$rC = new ReflectionClass('MyFirstClass');
You can now find out in which file it was declared, and which methods are in it :
var_dump($rC->getFileName());
var_dump($rC->getMethods());
Which will get you :
string '/home/squale/developpement/tests/temp/temp-2.php' (length=48)
array
0 => &
object(ReflectionMethod)[2]
public 'name' => string '__construct' (length=11)
public 'class' => string 'MyFirstClass' (length=12)
1 => &
object(ReflectionMethod)[3]
public 'name' => string 'glop' (length=4)
public 'class' => string 'MyFirstClass' (length=12)
And now, to get informations on each method :
foreach ($rC->getMethods() as $rM) {
var_dump($rM, $rM->getParameters());
echo '-----';
}
You'll get :
object(ReflectionMethod)[3]
public 'name' => string '__construct' (length=11)
public 'class' => string 'MyFirstClass' (length=12)
array
0 => &
object(ReflectionParameter)[4]
public 'name' => string 'arg1' (length=4)
1 => &
object(ReflectionParameter)[5]
public 'name' => string 'arg2' (length=4)
-----
object(ReflectionMethod)[2]
public 'name' => string 'glop' (length=4)
public 'class' => string 'MyFirstClass' (length=12)
array
0 => &
object(ReflectionParameter)[5]
public 'name' => string 'a' (length=1)
From there, you should be able to dig a bit more ; and arrive to what you first asked ;-)
As a sidenote : there is one thing I have no idea about is : "how to find which classes / methods are declared in a given file" :-(
If anyone has an idea, it'll be welcome !

PHP architecture, and pass-by-reference vs pass-by-value

Seeking suggestions from PHP architects!
I'm not terribly familiar with PHP but have taken over maintenance of a large analytics package written in the language. The architecture is designed to read reported data into large key/value arrays, which are passed through various parsing modules to extract those report parameters known to each of those modules. Known parameters are removed from the master array, and any leftovers which were not recognized by any of the modules, are dumped into a kind of catch-all report showing the "unknown" data points.
There are a few different methods being used to call these parser modules, and I would like to know which if any are considered to be "proper" PHP structure. Some are using pass-by-reference, others pass-by-value, some are functions, some are objects. All of them modify the input parameter in some way.
A super-simplified example follows:
#!/usr/bin/php
<?php
$values = Array("a"=>1, "b"=>2, "c"=>3, "d"=>4 );
class ParserA {
private $a = null;
public function __construct(&$myvalues) {
$this->a = $myvalues["a"];
unset($myvalues["a"]);
}
public function toString() { return $this->a; }
}
// pass-by-value
function parse_b($myvalues) {
$b = $myvalues["b"];
unset($myvalues["b"]);
return Array($b, $myvalues);
}
// pass-by-reference
function parse_c(&$myvalues) {
echo "c=".$myvalues["c"]."\n";
unset($myvalues["c"]);
}
// Show beginning state
print_r($values);
// will echo "1" and remove "a" from $values
$a = new ParserA($values);
echo "a=".$a->toString()."\n";
print_r($values);
// w ill echo "2" and remove "b" from $values
list($b, $values) = parse_b($values);
echo "b=".$b."\n";
print_r($values);
// will echo "3" and remove "c" from $values
parse_c($values);
print_r($values);
?>
The output will be:
Array
(
[a] => 1
[b] => 2
[c] => 3
[d] => 4
)
a=1
Array
(
[b] => 2
[c] => 3
[d] => 4
)
b=2
Array
(
[c] => 3
[d] => 4
)
c=3
Array
(
[d] => 4
)
I'm really uncomfortable having so many different call methods in use, some of which have hidden effects on the call function parameters using "&pointer"-style functions, some requiring the main body to write their output, and some writing their output independently.
I would prefer to choose a single methodology and stick with it. In order to do so, I would also like to know which is most efficient; my reading of the PHP documentation indicates that since it uses copy-on-write, there shouldn't be much performance difference between using pointers to vs passing the object directly and re-reading a return value. I would also prefer to use the object-oriented structure, but am uncomfortable with the hidden changes being made to the input parameter on the constructor.
Of the three calling methods, ParserA(), parse_b(), and parse_c(), which if any is the most appropriate style?
I'm not really an expert in PHP but from my experience passing by value is better. This way code won't have side effects and that mean it will be easier to understand and maintain and do all sorts of crazy things on it, like using it as callback for map function. So I'm all for parse_b way of doing things.
FYI: In PHP, objects are always passed by reference, no matter what. Also if you have an array with objects and scalar values in it, the scalar values are passed by value, but the objects by reference.
As a general rule in PHP, do not use references unless you really have to.
references in PHP are also not what most people expect them to be:
"References in PHP are a means to access the same variable content by different names. They are not like C pointers; instead, they are symbol table aliases.""
see also: php.net: What References Are
So in short:
The proper way of handling this PHP is using creating an object that passes the variables around by value or manipulating the array with array_map (array_map allows you to apply a callback function to the elements an array.)
I would vote against the methods proposed in general, but of them, I think parse_b has the best idea.
I think it would be better design to wrap the "data" array in a class that could let you "pop" a key out of it easily. So the parser ends up looking like:
class ParserA {
private $a = null;
public function __construct(My_Data_Class $data) {
$this->a = $data->popValue("a");
}
public function toString() { return $this->a; }
}
And a sample implementation
class My_Data_Class {
protected $_data;
public function __construct(array $data) {
$this->_data = $data;
}
public function popValue($key) {
if (isset($this->_data[$key])) {
$value = $this->_data[$key];
unset($this->_data[$key]);
return $value;
}
}
}

Categories