I have few helpers - I want to redclare each helper's method as a lambda anonymous function.
I'm trying to do it by getting the helpers methods, and then doing an eval function, but it wont work, im getting parse error..
My current code:
foreach($this->helpers as $helper)
{
include(master_path . 'helpers/'.$helper.'Helper.php');
$helperClass = new applicationHelper();
$methods = get_class_methods($helperClass);
foreach($methods as $method )
{
eval ( "\$$method = function (\$text) {
\$helperClass->$method(\$text);
}");
}
}
Due to efficiency fears - I'd like a better solution if you know it, thanks!
Thanks Guys!
That should work:
foreach($methods as $method )
{
$$method = function($text) use ($method, $helperClass) {
return $helperClass->$method($text);
}
}
But still dont know why are you doing that.
EDIT
PHP 5.3.x needed -> look here Anonymous funcions
foreach ($this->helpers as $helper) {
include(master_path . 'helpers/'.$helper.'Helper.php');
$helperClass = new applicationHelper();
foreach (get_class_methods($helperClass) as $method) {
$$method = function($text) use($helperClass, $method) {
$helperClass->$method($text);
};
}
}
That get's rid of the slow eval.
Related
I wanted to create closure with dynamic code. To do that I wrote below code :-
function generateFunction ($class, $method){
$code = "require_once 'Init.php';";
$code = '$model = new '.$class.'();';
$code .= '$model->'.$method.'();';
return function() use(&$code){
return eval($code);
};
}
I know eval is evil but unable to find any alternative yet.
To get the function in variable I used below code :-
$myNewFunction = generateFunction ('svn', 'update');
Now I want to run this function by passing it as argument to my PHP file. But this function has same body on the output while I expected it to be like below.
function(){return eval(require_once 'Init.php';$model = new svn(); $model->update())}
Basically this need arise when I decided to integrate the Jobby.
Basically this need arise when I decided to integrate the Jobby.
I assume you want to create callback functions dynamically. Then your code is complete overkill and also doesn't need eval at all. You can get the same results by passing this as callback:
$callback = array(new SVN, 'update');
That's essentially all your code does anyway. Though with the difference that SVN is instantiated here, not when the callback is triggered. For an eval-free version of your code, this'll do:
function generateFunction($class, $method) {
return function () use ($class, $method) {
require_once 'Init.php';
$model = new $class;
return $model->$method();
};
}
To complete your answers, here is a complete example with jobby :
$jobby = new \Jobby\Jobby();
$WebSitesSchedule = new WebSitesSchedule();
$WebSitesSchedule->load_all();
foreach ($WebSitesSchedule as $WebSiteSchedule)
{
$Url = $WebSiteSchedule->ScheduleAction.'?'.$WebSiteSchedule->ScheduleParameters;
$jobby->add( "CmsSchedule_".strval($WebSiteSchedule->ScheduleID), array(
'command' => generateFunction($Url),
'schedule' => $WebSiteSchedule->ScheduleCron,
'output' => '/PATH/log/CmsSchedule.log',
'enabled' => true,
'debug' => true,
'recipients' => 'toto#gmail.com'
));
}
function generateFunction($Url)
{
return function () use ($Url)
{
$Result = Proxy::curl_request($Url);
if($Result["status"]==="success")
{
print_r($Result);
return TRUE;
}
else
{
print_r($Result);
return FALSE;
}
};
}
$jobby->run();
In your case you don't need to use eval(). You have to use call_user_func (or call_user_func_array) in conjunction with class_exists and method_exists instead.
require_once 'Init.php';
function generateFunction ($class, $method) {
if (!class_exists($class)) return false;
$model = new $class();
return method_exists($model, $method)? array($model, $method) : false;
}
$myNewFunction = generateFunction ('svn', 'update');
if ($myNewFunction) call_user_func($myNewFunction);
I have some code like this
$form_names = GFFormsModel::get_forms();
foreach ($form_names as $form) {
add_action("gform_pre_submission_".$form->id, "format_ecp_event_meta_from_gravity");
function format_ecp_event_meta_from_gravity(){
}
}
Since i'm using foreach loop functions get duplicated. So is there a way to make the function unique using $form->id ?
I mean i want the function names like this
function format_ecp_event_meta_from_gravity_{$form->id}(){
}
Can someone help me?
Thanks
Use closures:
$form_names = GFFormsModel::get_forms();
foreach ($form_names as $form) {
$func = function() {
...
};
add_action("gform_pre_submission_".$form->id, $func);
}
Right now I'm trying to write a function that would allow me to access member functions. The code in question looks a little like this:
protected $formName;
protected $formClass;
protected $formAction;
protected $formMethod;
protected $formObjArray = array(); //outputs in order. So far it should only take newLine, selectTag, inputTag, textTag.
protected $submitBtnVal;
protected $encType;
function __construct($args) {
$this->formName = $args['formName'];
$this->formAction = $args['formAction'];
if (isset($args['formClass'])) $this->formClass = $args['formClass'];
if (isset($args['encType'])) $this->encType = $args['encType'];
//default should be POST. Hell, you should never really be using GET for this..
//also, the default submit value is Submit
$this->formMethod = isset($args['formMethod']) ? $args['formMethod'] : "POST";
$this->submitBtnVal = isset($args['submitBtnVal']) ? $args['submitBtnVal'] : "Submit";
}
//get functions
function getFormName () { return $this->formName; }
function getFormAction () { return $this->formAction; }
function getFormMethod () { return $this->formMethod; }
function getSubmitBtnVal () { return $this->submitBtnVal; }
function getEncType () { return $this->encType; }
//set functions
function setFormName ($newName) { $this->fromName = $newName; }
function setFormAction ($newAction) { $this->formAction = $newAction; }
function setFormMethod ($newMethod) { $this->formMethod = $newMethod; }
function setEncType ($newEType) { $this->encType = $newEType; }
function addTag($newTag) {
if ($newTag instanceof formTag || $newTag instanceof fieldSetCont || $newTag instanceof newLine
|| $newTag instanceof noteTag)
$this->formObjArray[] = $newTag;
else throw new Exception ("You did not add a compatible tag.");
}
I'd like to be able to call $myForm->getTagByName("nameA")->setRequired(true);
How would I do that? Or would I need to do something more like..
$tagID = $myForm->getTagByName("nameA");
$myForm->tagArray(tagID)->setRequired(true);
Nothing in your code seems to be protected so you should have no trouble accessing any of it.
It looks like all your tags are in $formObjArray so it should be trivial to filter than array and return tags that match the name you've passed in. The trouble you will have is that, getTagByName really should be getTagsByName and should return an array because you can have more than one tag with the same name. Since it will return an array, you can not call setRequired on the return value, arrays don't have such a method. You'll need to do it more like:
$tags = $myForm->getTagsByName("nameA");
foreach ($tags as $tag) {
$tag->setRequired(true);
}
Exactly what are you stuck on? Maybe I don't understand the question very well.
So maybe the filtering has you stuck? Try this (if you you're using at least php 5.3)
function getTagsByName($tagname)
{
return array_filter($this->formObjArray, function($tag) use($tagname) {
return $tag->getName() == $tagname;
});
}
No ifs or switches.
Prior to 5.3, you don't have lambda functions so you need to do it differently. There are several options but this may be the simplest to understand:
function getTagsByName($tagname)
{
$out = array();
foreach ($this->formObjArray as &$tag) {
if ($tag->getName() == $tagname) {
$out[] = $tag;
}
}
return $out;
}
In your addTag method, you are storing new tags in $this->formObjArray using the [] notation, which will just append the new tag to the end of the array. If your tag objects all have a getName() method, then you can do something like this:
$this->formObjArray[$newTag->getName()] = $newTag;
Then, you can easily add a getTagByName() method:
public function getTagByName($name) {
if (array_key_exists($name, $this->formObjArray) {
return $this->formObjArray($name);
}
else {
return null;
}
}
Please beware of the solutions suggesting you to iterate through all the tags in your array! This could become very costly as your form gets larger.
If you need to use the [] construct because the order of the elements added is important, then you can still maintain a separate index by name, $this->tagIndex, that will be an associative array of name => tag. Since you are storing object references, they will not be using much space. Assuming that getTagByName will be used many times, this will save you a lot of resources over iterating the tags array on every call to getTagByName.
In that case, your addTag method would look like this:
$this->formObjArray[] = $newTag;
$this->tagIndex[$newTag->getName()] = $newTag; // it seems that you're doubling the memory needed, but you're only storing object references so this is safe
EDIT : Here is some modified code to account for the fact that multiple tags can have the same name:
In your addTag() method, do:
$this->formObjArray[] = $newTag;
$tag_name = $newTag->getName();
if (!array_key_exists($tag_name, $this->tagIndex)) {
$this->tagIndex[$tag_name] = array();
}
$this->tagIndex[$tag_name][] = $newTag
You can then rename getTagByName to getTagsByName and get the expected result.
As mentioned in the comments, this is only useful if you will call getTagsByName multiple times. You are trading a little additional memory usage in order to get quicker lookups by name.
So, I have a object with structure similar to below, all of which are returned to me as stdClass objects
$person->contact->phone;
$person->contact->email;
$person->contact->address->line_1;
$person->contact->address->line_2;
$person->dob->day;
$person->dob->month;
$person->dob->year;
$album->name;
$album->image->height;
$album->image->width;
$album->artist->name;
$album->artist->id;
etc... (note these examples are not linked together).
Is it possible to use variable variables to call contact->phone as a direct property of $person?
For example:
$property = 'contact->phone';
echo $person->$property;
This will not work as is and throws a E_NOTICE so I am trying to work out an alternative method to achieve this.
Any ideas?
In response to answers relating to proxy methods:
And I would except this object is from a library and am using it to populate a new object with an array map as follows:
array(
'contactPhone' => 'contact->phone',
'contactEmail' => 'contact->email'
);
and then foreaching through the map to populate the new object. I guess I could envole the mapper instead...
If i was you I would create a simple method ->property(); that returns $this->contact->phone
Is it possible to use variable variables to call contact->phone as a direct property of $person?
It's not possible to use expressions as variable variable names.
But you can always cheat:
class xyz {
function __get($name) {
if (strpos($name, "->")) {
foreach (explode("->", $name) as $name) {
$var = isset($var) ? $var->$name : $this->$name;
}
return $var;
}
else return $this->$name;
}
}
try this code
$property = $contact->phone;
echo $person->$property;
I think this is a bad thing to to as it leads to unreadable code is is plain wrong on other levels too, but in general if you need to include variables in the object syntax you should wrap it in braces so that it gets parsed first.
For example:
$property = 'contact->phone';
echo $person->{$property};
The same applies if you need to access an object that has disalowed characters in the name which can happen with SimpleXML objects regularly.
$xml->{a-disallowed-field}
If it is legal it does not mean it is also moral. And this is the main issue with PHP, yes, you can do almost whatever you can think of, but that does not make it right. Take a look at the law of demeter:
Law of Demeter
try this if you really really want to:
json_decode(json_encode($person),true);
you will be able to parse it as an array not an object but it does your job for the getting not for the setting.
EDIT:
class Adapter {
public static function adapt($data,$type) {
$vars = get_class_vars($type);
if(class_exists($type)) {
$adaptedData = new $type();
} else {
print_R($data);
throw new Exception("Class ".$type." does not exist for data ".$data);
}
$vars = array_keys($vars);
foreach($vars as $v) {
if($v) {
if(is_object($data->$v)) {
// I store the $type inside the object
$adaptedData->$v = Adapter::adapt($data->$v,$data->$v->type);
} else {
$adaptedData->$v = $data->$v;
}
}
}
return $adaptedData;
}
}
OOP is much about shielding the object's internals from the outside world. What you try to do here is provide a way to publicize the innards of the phone through the person interface. That's not nice.
If you want a convenient way to get "all" the properties, you may want to write an explicit set of convenience functions for that, maybe wrapped in another class if you like. That way you can evolve the supported utilities without having to touch (and possibly break) the core data structures:
class conv {
static function phone( $person ) {
return $person->contact->phone;
}
}
// imagine getting a Person from db
$person = getpersonfromDB();
print conv::phone( $p );
If ever you need a more specialized function, you add it to the utilities. This is imho the nices solution: separate the convenience from the core to decrease complexity, and increase maintainability/understandability.
Another way is to 'extend' the Person class with conveniences, built around the core class' innards:
class ConvPerson extends Person {
function __construct( $person ) {
Person::__construct( $person->contact, $person->name, ... );
}
function phone() { return $this->contact->phone; }
}
// imagine getting a Person from db
$person = getpersonfromDB();
$p=new ConvPerson( $person );
print $p->phone();
You could use type casting to change the object to an array.
$person = (array) $person;
echo $person['contact']['phone'];
In most cases where you have nested internal objects, it might be a good time to re-evaluate your data structures.
In the example above, person has contact and dob. The contact also contains address. Trying to access the data from the uppermost level is not uncommon when writing complex database applications. However, you might find your the best solution to this is to consolidate data up into the person class instead of trying to essentially "mine" into the internal objects.
As much as I hate saying it, you could do an eval :
foreach ($properties as $property) {
echo eval("return \$person->$property;");
}
Besides making function getPhone(){return $this->contact->phone;} you could make a magic method that would look through internal objects for requested field. Do remember that magic methods are somewhat slow though.
class Person {
private $fields = array();
//...
public function __get($name) {
if (empty($this->fields)) {
$this->fields = get_class_vars(__CLASS__);
}
//Cycle through properties and see if one of them contains requested field:
foreach ($this->fields as $propName => $default) {
if (is_object($this->$propName) && isset($this->$propName->$name)) {
return $this->$propName->$name;
}
}
return NULL;
//Or any other error handling
}
}
I have decided to scrap this whole approach and go with a more long-winded but cleaner and most probably more efficient. I wasn't too keen on this idea in the first place, and the majority has spoken on here to make my mind up for me. Thank for you for your answers.
Edit:
If you are interested:
public function __construct($data)
{
$this->_raw = $data;
}
public function getContactPhone()
{
return $this->contact->phone;
}
public function __get($name)
{
if (isset($this->$name)) {
return $this->$name;
}
if (isset($this->_raw->$name)) {
return $this->_raw->$name;
}
return null;
}
In case you use your object in a struct-like way, you can model a 'path' to the requested node explicitly. You can then 'decorate' your objects with the same retrieval code.
An example of 'retrieval only' decoration code:
function retrieve( $obj, $path ) {
$element=$obj;
foreach( $path as $step ) {
$element=$element[$step];
}
return $element;
}
function decorate( $decos, &$object ) {
foreach( $decos as $name=>$path ) {
$object[$name]=retrieve($object,$path);
}
}
$o=array(
"id"=>array("name"=>"Ben","surname"=>"Taylor"),
"contact"=>array( "phone"=>"0101010" )
);
$decorations=array(
"phone"=>array("contact","phone"),
"name"=>array("id","name")
);
// this is where the action is
decorate( $decorations, &$o);
print $o->name;
print $o->phone;
(find it on codepad)
If you know the two function's names, could you do this? (not tested)
$a = [
'contactPhone' => 'contact->phone',
'contactEmail' => 'contact->email'
];
foreach ($a as $name => $chain) {
$std = new stdClass();
list($f1, $f2) = explode('->', $chain);
echo $std->{$f1}()->{$f2}(); // This works
}
If it's not always two functions, you could hack it more to make it work. Point is, you can call chained functions using variable variables, as long as you use the bracket format.
Simplest and cleanest way I know of.
function getValueByPath($obj,$path) {
return eval('return $obj->'.$path.';');
}
Usage
echo getValueByPath($person,'contact->email');
// Returns the value of that object path
I'm sure there's a very easy explanation for this. What is the difference between this:
function barber($type){
echo "You wanted a $type haircut, no problem\n";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
... and this (and what are the benefits?):
function barber($type){
echo "You wanted a $type haircut, no problem\n";
}
barber('mushroom');
barber('shave');
Always use the actual function name when you know it.
call_user_func is for calling functions whose name you don't know ahead of time but it is much less efficient since the program has to lookup the function at runtime.
Although you can call variable function names this way:
function printIt($str) { print($str); }
$funcname = 'printIt';
$funcname('Hello world!');
there are cases where you don't know how many arguments you're passing. Consider the following:
function someFunc() {
$args = func_get_args();
// do something
}
call_user_func_array('someFunc',array('one','two','three'));
It's also handy for calling static and object methods, respectively:
call_user_func(array('someClass','someFunc'),$arg);
call_user_func(array($myObj,'someFunc'),$arg);
the call_user_func option is there so you can do things like:
$dynamicFunctionName = "barber";
call_user_func($dynamicFunctionName, 'mushroom');
where the dynamicFunctionName string could be more exciting and generated at run-time. You shouldn't use call_user_func unless you have to, because it is slower.
With PHP 7 you can use the nicer variable-function syntax everywhere. It works with static/instance functions, and it can take an array of parameters. More info at https://trowski.com/2015/06/20/php-callable-paradox
$ret = $callable(...$params);
I imagine it is useful for calling a function that you don't know the name of in advance...
Something like:
switch($value):
{
case 7:
$func = 'run';
break;
default:
$func = 'stop';
break;
}
call_user_func($func, 'stuff');
There are no benefits to call it like that, the word user mean it is for multiple user, it is useful to create modification without editing in core engine.
it used by wordpress to call user function in plugins
<?php
/* main.php */
require("core.php");
require("my_plugin.php");
the_content(); // "Hello I live in Tasikmalaya"
...
<?php
/* core.php */
$listFunc = array();
$content = "Hello I live in ###";
function add_filter($fName, $funct)
{
global $listFunc;
$listFunc[$fName] = $funct;
}
function apply_filter($funct, $content)
{
global $listFunc;
foreach ($listFunc as $key => $value)
{
if ($key == $funct and is_callable($listFunc[$key]))
{
$content = call_user_func($listFunc[$key], $content);
}
}
echo $content;
}
function the_content()
{
global $content;
$content = apply_filter('the_content', $content);
echo $content;
}
....
<?php
/* my_plugin.php */
function changeMyLocation($content){
return str_replace('###', 'Tasikmalaya', $content);
}
add_filter('the_content', 'changeMyLocation');
in your first example you're using function name which is a string. it might come from outside or be determined on the fly. that is, you don't know what function will need to be run at the moment of the code creation.
When using namespaces, call_user_func() is the only way to run a function you don't know the name of beforehand, for example:
$function = '\Utilities\SearchTools::getCurrency';
call_user_func($function,'USA');
If all your functions were in the same namespace, then it wouldn't be such an issue, as you could use something like this:
$function = 'getCurrency';
$function('USA');
Edit:
Following #Jannis saying that I'm wrong I did a little more testing, and wasn't having much luck:
<?php
namespace Foo {
class Bar {
public static function getBar() {
return 'Bar';
}
}
echo "<h1>Bar: ".\Foo\Bar::getBar()."</h1>";
// outputs 'Bar: Bar'
$function = '\Foo\Bar::getBar';
echo "<h1>Bar: ".$function()."</h1>";
// outputs 'Fatal error: Call to undefined function \Foo\Bar::getBar()'
$function = '\Foo\Bar\getBar';
echo "<h1>Bar: ".$function()."</h1>";
// outputs 'Fatal error: Call to undefined function \foo\Bar\getBar()'
}
You can see the output results here: https://3v4l.org/iBERh it seems the second method works for PHP 7 onwards, but not PHP 5.6.