Convert a class to a function when there's __construct() elements - php

I am learning PHP (constantly) and I created some time ago a class that handles translations. I want to emulate gettext but getting the translated strings from a database. However, now that I see it again, I don't like that, being a class, to call it I need to use $Translate->text('String_keyword');. I wouldn't like either to have to use $T->a('String_keyword'); since that's completely not intuitive.
I've been thinking a lot on how to make it to be called with a simple _('String_keyword'), gettext style but, from what I've learned from SO, I haven't been able to find a 'great' way to accomplish this. I need to pass somehow the default language to the function, I don't want to pass it every time I call it as it would be _('String_keyword', $User->get('Language'))). I also don't want to include the user-detection script in the _() function, as it only needs to be run once and not every time.
The easiest one would be to use GLOBALS, but I've learned here that they are completely-utterly forbidden (could this be the only case where I can use them?), then I thought to DEFINE a variable with the user's language like define ( USER_LANGUAGE , $User->get('Language') ), but it seems just to be the same as a global. These are the 2 main options I can see, I know there are some other ways like Dependency Injection but they seem to add just too much complication for a so simple request and I haven't yet had time to dig into them.
I was thinking about creating a wrapper first to test it out. Something like this:
function _($Id, $Arg = null)
{
$Translate = new Translate (USER_LANGUAGE);
return $Translate -> text($Id, $Arg)
}
Here is the translation code. The language is detected before and passed to the object when created.
// Translate text strings
// TO DO: SHOULD, SHOULD change it to PDO! Also, merge the 2 tables into 1
class Translate
{
private $Lang;
function __construct ($Lang)
{
$this->Lang = $Lang;
}
// Clever. Adds the translation so when codding I don't get annoyed.
private function add ($Id, $Text)
{
$sql="INSERT INTO htranslations (keyword, en, page, last) VALUES ('$Id', '$Text', '".$_SERVER['PHP_SELF']."', now())";
mysql_query($sql);
}
private function retrieve ( $Id )
{
$table = is_int ($Id) ? "translations" : "htranslations"; // A small tweak to support the two tables, but they should be merged.
$results = mysql_query ("SELECT ".mysql_real_escape_string($this->Lang)." FROM ".$table." WHERE keyword='".mysql_real_escape_string($Id)."'");
$row = mysql_fetch_assoc ($results);
return mysql_num_rows ($results) ? stripslashes ($row[$this->Lang]) : null;
}
// If needed to insert a name, for example, pass it in the $Arg
public function text($Id, $Arg = null)
{
$Text = $this->retrieve($Id);
if (empty($Text))
{
$Text = str_replace("_", " ", $Id); // If not found, replace all "_" with " " from the input string.
$this->add($Id, $Text);
}
return str_replace("%s", $Arg, $Text); // Not likely to have more than 2 variables into a single string.
}
}
How would you accomplish this in a proper yet simple (for coding) way? Are any of the proposed methods valid or can you come with a better one?

If the problem is simply that
$Translate->text('String_keyword');
feels to long, then consider making the Translate object into a Functor by implementing __invoke:
class Translate
{
// all your PHP code you already have
public function __invoke($keyword, $Arg = null)
{
return $this->text($keyword, $Arg)
}
}
You can then instantiate the object regularly with all the required dependencies and settings and call it:
$_ = new Translate(/* whatever it needs */);
echo $_('Hallo Welt');
That would not introduce the same amount of coupling and fiddling with the global scope as you currently consider to introduce through a wrapper function or as the Registry/Singleton solution suggested elsewhere. The only drawback is the non-speaking naming of the object variable as $_().

I would use a registry or make Translate a singleton. When i first initalize it i would pass in the language which would be dont in the bootstrap phase of the request. Then i would add methods to change the language later if necessary.
After doing that your function becomes pretty simple:
// singleton version
function _($id, $arg = null) {
return Translate::getInstance()->text($id, $arg);
}
// registry version
function _($id, $arg = null) {
return Registry::get('Translate')->text($id, $arg);
}
And then in your bootstap phase you would do something like:
$lang = get_user_lang(); // replace with however you do this
//registry version
Registry::set('Tranlaste', new Translate($lang));
// or the singleton version
// youd use create instance instead of getInstance
// so you can manage the case where you try to call
// getInstance before a language is set
Translate::createInstance($lang);

Related

How to store a name of a function in an array and call it when needed? [duplicate]

I need to be able to call a function, but the function name is stored in a variable, is this possible? e.g:
function foo ()
{
//code here
}
function bar ()
{
//code here
}
$functionName = "foo";
// I need to call the function based on what is $functionName
$functionName() or call_user_func($functionName)
My favorite version is the inline version:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
You can place variables or expressions inside the brackets too!
Solution: Use PHP7
Note: For a summarized version, see TL;DR at the end of the answer.
Old Methods
Update: One of the old methods explained here has been removed. Refer to other answers for explanation on other methods, it isn't covered here. By the way, if this answer doesn't help you, you should return upgrading your stuff. PHP 5.6 support has ended in January 2019 (now even PHP 7.2 and 7.3 are not being supported). See supported versions for more information.
As others mentioned, in PHP5 (and also in newer versions like PHP7) we could use variables as function names, use call_user_func() and call_user_func_array(), etc.
New Methods
As of PHP7, there are new ways introduced:
Note: Everything inside <something> brackets means one or more expressions to form something, e.g. <function_name> means expressions forming a function name.
Dynamic Function Call: Function Name On-the-fly
We can form a function name inside parentheses in just one go:
(<function_name>)(arguments);
For example:
function something(): string
{
return "something";
}
$bar = "some_thing";
(str_replace("_", "", $bar))(); // something
// Possible, too; but generally, not recommended, because makes your
// code more complicated
(str_replace("_", "", $bar))()();
Note: Although removing the parentheses around str_replace() is not an error, putting parentheses makes code more readable. However, you cannot do that sometimes, e.g. while using . operator. To be consistent, I recommend you to put the parentheses always.
Dynamic Function Call: Callable Property
A useful example would be in the context of objects: If you have stored a callable in a property, you have to call it this way:
($object->{<property_name>})();
As a simple example:
// Suppose we're in a class method context
($this->eventHandler)();
Obviously, calling it as $this->eventHandler() is plain wrong: By that you mean calling a method named eventHandler.
Dynamic Method Call: Method Name On-the-fly
Just like dynamic function calls, we can do the same way with method calls, surrounded by curly braces instead of parentheses (for extra forms, navigate to TL;DR section):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
See it in an example:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Dynamic Method Call: The Array Syntax
A more elegant way added in PHP7 is the following:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
As an example:
class Foo
{
public function nonStaticCall()
{
echo "Non-static call";
}
public static function staticCall()
{
echo "Static call";
}
}
$x = new X();
[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call
Note: The benefit of using this method over the previous one is that, you don't care about the call type (i.e. whether it's static or not).
Note: If you care about performance (and micro-optimizations), don't use this method. As I tested, this method is really slower than other methods (more than 10 times).
Extra Example: Using Anonymous Classes
Making things a bit complicated, you could use a combination of anonymous classes and the features above:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
TL;DR (Conclusion)
Generally, in PHP7, using the following forms are all possible:
// Everything inside `<something>` brackets means one or more expressions
// to form something
// Dynamic function call via function name
(<function_name>)(arguments);
// Dynamic function call on a callable property
($object->{<property_name>})(arguments);
// Dynamic method call on an object
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments);
(<object>)::{<method_name>}(arguments);
// Dynamic method call, statically
ClassName::{<method_name>}(arguments);
(<class_name>)::{<method_name>}(arguments);
// Dynamic method call, array-like (no different between static
// and non-static calls
[<object>, <method_name>](arguments);
// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments);
Special thanks to this PHP talk.
Yes, it is possible:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Source: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
As already mentioned, there are a few ways to achieve this with possibly the safest method being call_user_func() or if you must you can also go down the route of $function_name(). It is possible to pass arguments using both of these methods as so
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
If the function you are calling belongs to an object you can still use either of these
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
However if you are going to use the $function_name() method it may be a good idea to test for the existence of the function if the name is in any way dynamic
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
A few years late, but this is the best manner now imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
In case someone else is brought here by google because they were trying to use a variable for a method within a class, the below is a code sample which will actually work. None of the above worked for my situation. The key difference is the & in the declaration of $c = & new... and &$c being passed in call_user_func.
My specific case is when implementing someone's code having to do with colors and two member methods lighten() and darken() from the csscolor.php class. For whatever reason, I wanted to have the same code be able to call lighten or darken rather than select it out with logic. This may be the result of my stubbornness to not just use if-else or to change the code calling this method.
$lightdark="lighten"; // or optionally can be darken
$color="fcc"; // a hex color
$percent=0.15;
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);
Note that trying anything with $c->{...} didn't work. Upon perusing the reader-contributed content at the bottom of php.net's page on call_user_func, I was able to piece together the above. Also, note that $params as an array didn't work for me:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
This above attempt would give a warning about the method expecting a 2nd argument (percent).
For the sake of completeness, you can also use eval():
$functionName = "foo()";
eval($functionName);
However, call_user_func() is the proper way.
Dynamic function names and namespaces
Just to add a point about dynamic function names when using namespaces.
If you're using namespaces, the following won't work except if your function is in the global namespace:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
What to do?
You have to use call_user_func() instead:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Complementing the answer of #Chris K if you want to call an object's method, you can call it using a single variable with the help of a closure:
function get_method($object, $method){
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
class test{
function echo_this($text){
echo $text;
}
}
$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello'); //Output is "Hello"
I posted another example here
Use the call_user_func function.
What I learnt from this question and the answers. Thanks all!
Let say I have these variables and functions:
$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";
$friend = "John";
$datas = array(
"something"=>"how are you?",
"to"=>"Sarah"
);
function sayHello()
{
echo "Hello!";
}
function sayHelloTo($to)
{
echo "Dear $to, hello!";
}
function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
To call function without arguments
// Calling sayHello()
call_user_func($functionName1);
Hello!
To call function with 1 argument
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Dear John, hello!
To call function with 1 or more arguments
This will be useful if you are dynamically calling your functions and each function have different number of arguments. This is my case that I have been looking for (and solved). call_user_func_array is the key
// You can add your arguments
// 1. statically by hard-code,
$arguments[0] = "how are you?"; // my $something
$arguments[1] = "Sarah"; // my $to
// 2. OR dynamically using foreach
$arguments = NULL;
foreach($datas as $data)
{
$arguments[] = $data;
}
// Calling saySomethingTo("how are you?", "Sarah")
call_user_func_array($functionName3, $arguments);
Dear Sarah, how are you?
Yay bye!
If you were in a object context trying to call a function dynamically please try something like this code bellow:
$this->{$variable}();
Following code can help to write dynamic function in PHP.
now the function name can be dynamically change by variable '$current_page'.
$current_page = 'home_page';
$function = #${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
The easiest way to call a function safely using the name stored in a variable is,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
I have used like below to create migration tables in Laravel dynamically,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Considering some of the excellent answers given here, sometimes you need to be precise.
For example.
if a function has a return value eg (boolean,array,string,int,float
e.t.c).
if the function has no return value check
if the function exists
Let's look at its credit to some of the answers given.
Class Cars{
function carMake(){
return 'Toyota';
}
function carMakeYear(){
return 2020;
}
function estimatedPriceInDollar{
return 1500.89;
}
function colorList(){
return array("Black","Gold","Silver","Blue");
}
function carUsage(){
return array("Private","Commercial","Government");
}
function getCar(){
echo "Toyota Venza 2020 model private estimated price is 1500 USD";
}
}
We want to check if method exists and call it dynamically.
$method = "color List";
$class = new Cars();
//If the function have return value;
$arrayColor = method_exists($class, str_replace(' ', "", $method)) ? call_user_func(array($this, $obj)) : [];
//If the function have no return value e.g echo,die,print e.t.c
$method = "get Car";
if(method_exists($class, str_replace(' ', "", $method))){
call_user_func(array($class, $method))
}
Thanks
One unconventional approach, that came to my mind is, unless you are generating the whole code through some super ultra autonomous AI which writes itself, there are high chances that the functions which you want to "dynamically" call, are already defined in your code base. So why not just check for the string and do the infamous ifelse dance to summon the ...you get my point.
eg.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Even switch-case can be used if you don't like the bland taste of ifelse ladder.
I understand that there are cases where the "dynamically calling the function" would be an absolute necessity (Like some recursive logic which modifies itself). But most of the everyday trivial use-cases can just be dodged.
It weeds out a lot of uncertainty from your application, while giving you a chance to execute a fallback function if the string doesn't match any of the available functions' definition. IMHO.
I dont know why u have to use that, doesnt sound so good to me at all, but if there are only a small amount of functions, you could use a if/elseif construct.
I dont know if a direct solution is possible.
something like
$foo = "bar";
$test = "foo";
echo $$test;
should return bar, you can try around but i dont think this will work for functions

OOP shortening class

This is not so much a question about execution as it is a question about improving code. I am a 2nd year student, we started to touch on OOP recently and I am finally getting the hold of it....sort of.
I realize this is a very basic question, but what better place to learn from some of the best.
My Question
I have a class which creates a new match. My problem is that I am sure the code is unnecessary long and can get much improved (just keep in mind it is beginner level).Specifically I would like to know:
Can I change the below into 1 setter and 1 getter method?
I would like to use the rand() function for match ID can I do this inside the setter function of setMatchId or should it be done outside of the class?
Thank you very much for taking the time to read this.
<?php
class match{
private $matchId;
private $team1;
private $team2;
private $venue;
function __construct($pMatchId, $pTeam1, $pTeam2, $pVenue){
$this->matchId = $pMatchId;
$this->team1 = $pTeam1;
$this->team2 = $pTeam2;
$this->venue = $pVenue;
}
function setMatchId($pMatchId){
$this->matchId = $pMatchId;
}
function getMatchId(){
return $this->matchId;
}
function setTeam1($pTeam1){
$this->team1 = $pTeam1;
}
function getTeam1(){
return $this->team1;
}
function setTeam2($pTeam2){
$this->team2 = $pTeam2;
}
function getTeam2(){
return $this->team2;
}
function setVenue($pVenue){
$this->venue = $pVenue;
}
function getVenue(){
return $this->venue;
}
} // c;lass match
$x = new match("1", "Patriots", "Chargers", "Newlands");
echo $x->getMatchId();
echo'<br />';
echo $x->getTeam1();
echo'<br />';
echo $x->getTeam2();
echo'<br />';
echo $x->getVenue();
?>
How often are teams or venues going to change for a match? I think you should get rid of the setters since you're already providing all the necessary data through your constructor.
You can indeed change your code to work with a single getter and setter methods, but I'd strongly discourage that. IDE's won't be able to assist you with code completion if you implement such methods but, most importantly, you should never blindly implement getters and setters in your entities if they have no reason to exist.
Let the design guide you on that. Start by passing everything your objects need through their constructors and only add getters/setters when you need them, not the other way around.
In terms of the randomness of the ID, you could use UUIDs for them. You could use this library to create them. I'd pass them through its constructor as well.
You can use __set and __get magic methods of PHP.
private $data = array(); // define property array
public function __set($name, $value) // set key and value in data property
{
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
public function __get($name) // get propery value
{
if(isset($this->data[$name])) {
return $this->data[$name];
}
}
You can write your existing code as below:-
class Match{
private $data = [];
function __construct($property=[]){
if(!empty($property)){
foreach($property as $key=>$value){
$this->__set($key,$value);
}
}
}
public function __set($name, $value) // set key and value in data property
{
// echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
public function __get($name) // get propery value
{
if(isset($this->data[$name])) {
return $this->data[$name];
}
}
}
Set properties using construct method
$x = new match(["matchId"=>"1", "team1"=>"Patriots","team2"=>"Chargers","venue"=>"Newlands"]);
echo '<pre>'; print_r($x);
Set properties without construct method
$x = new match;
$x->matchId = '1'; // 1
$x->team1 = 'team1'; // Patriots
$x->team2 = 'Chargers'; // Chargers
$x->venue = 'Newlands'; // Newlands
echo '<pre>'; print_r($x);
output:-
Match Object
(
[data:Match:private] => Array
(
[matchId] => 1
[team1] => Patriots
[team2] => Chargers
[venue] => Newlands
)
)
Now you can access and set propery by below way:-
// Get all properties values
echo $x->matchId; // 1
echo $x->team1; // Patriots
echo $x->team2; // Chargers
echo $x->venue; // Newlands
// Overwrite existing values
$x->team1 = 'new team1';
// Get updated value
echo $x->team1; // new team1
Hope it will help you :)
The first question:
Can I change the below into 1 setter and 1 getter method?
[EDIT] Reply to first comment:
You can, but you shouldn't.. To me it's better keep all setters and getters parted. You might want to get only a specific field when using your match object instance in your code. So if you need to get team1 or team2 it's better to have two different getter methods.
The second question:
I would like to use the rand() function for match ID can I do this inside the setter function of setMatchId or should it be done outside of the class?
Well, in my opinion, the best way of handle it is to disallow any access to the $matchId field making it private and removing any setter method.
Then, you should place the rand generation inside the constructor or, if you want to keep it parted in a specific function you could make a public getter like this:
public getMatchId(){
if ($this->matchId != null)
return $this->matchId
// Generate it with rand()
$this->matchId = rand()
return $this->matchId;
}
In the constructor then simply call the getMatchId() method.
By the way, this solution doesn't help you with getting a unique match identifier, to achieve that you should generate it not purely randomly but using something that is dependant of the informations of the Match (for instance you could use a combination of team1, team2 and venue) and/or keep track of used matchid (a static field or a database could be helpful)
[EDIT] Reply to second comment:
I'm using the if statement in the getter because this getter is thought to generate the $matchId when it's called for the first time, while it'll always return the previously generated $matchId for the other calls.
You question made me think of another possible implementation. If you want to avoid the if then you should generate the $matchId in the constructor.
This way should be fine:
public __construct($team1, $team2, $venue){
$this->matchId = rand();
$this->team1 = $team1;
$this->team2 = $team2;
$this->venue = $venue
}
public getMatchId(){
return $this->matchId;
}
There are multiple answers covering how to do setters and getters in various degrees of complexity and magic. In this post I would rather focus on the design quality of your class Match. This is based on the design idea related to what do you want to use your class for?
Some typical statements answering this question:
Keep record of a given match – In other words it needs to hold information related to one match, i.e. venue, homeTeam, awayTeam, result?, and possibly a matchId related to storing the result somewhere
Set the result of a match – You'll create the match, and then a little later you'll set the actual result of the match.
Store a match – If you don't store it anywhere it is kind of futile to keep track of the match, so most likely you would need some interface either to a database, or some mean to get all information related to a match ready for storing into a file or similar
Ability to retrieve the details of a match – If not getting all information at the same time, you could opt for a getter for the specific values you'll want.
For me I don't see the need for changing the team or venue, as that would mean a new match in my world. And I would definitively not implement a generic setter which would allow for setting whatever to whatever. A generic setter is a security risk in my world.
Alternate implementation
Adhering to the statements given I would write something similar to this:
<?php
class Match {
private $matchId;
private $homeTeam;
private $awayTeam;
private $venue;
private $result;
function __construct($venue, $homeTeam, $awayTeam, $matchId = NULL) {
$this->venue = $venue;
$this->homeTeam = $homeTeam;
$this->awayTeam = $awayTeam;
if (is_null($matchId)) {
$this->matchId = uniqid();
} else {
$this->matchId = $matchId;
}
// In PHP7: $this->matchId = $matchId ?: uniqid();
$this->result = "";
}
function setResult($result){
$this->result = $result;
}
function getAll(){
return array($this->venue, $this->homeTeam, $this->awayTeam,
$this->matchId, $this->result);
}
function __get($name) {
if (property_exist($this, $name)) {
return $this->$name;
}
}
function __set($name, $value) {
if (property_exist($this, $name)) {
$this->$name = $value;
}
}
?>
Some comments related to this code:
homeTeam and awayTeam – Having variables name team1 or team2 is a code smell, to me. I would either create an array for those, or find better names. In this case I opted for better names to make a clear distinction between the two variables.
__construct() – When creating a match the default value for matchId indicates that it will be set to a uniqid(). I consider this a better practice rather then using a random value. And it still allows for setting a specific match id if you want to provide this.
Based on the assumption that you don't know the result when the match is created, the result is set to an empty string for starters.
setResult() – As this is the only part of a match I foresee changing I provided a setter for this value.
getAll() – This returns an array of all the values, ready for storing somewhere. If you like this could easily be changed into a comma separated string or whatever format you would like for post-processing. It could even be a dictionary, but I just used a simple array to keep it simple.
__get() and __set() – Contrary to some of the other answers this getter (and setter) is a little safer to use as it verifies that the actual property is defined in this class using property_exist().
I'm not sure if I would actually have the generic setter, but if you'd like one, this is a better option as it doesn't allow for creation of new properties to your class at runtime.
Usage of class
Here is some simple usage of the class (if my untested code actually works, that is):
<!php
$m = new Match("Newlands", "Patriots", "Chargers");
// Time passes
$m->setResult("102-32");
echo 'In the game ' . $m->homeTeam . ' vs ' . $m->awayTeam
echo ' at ' . $m ->venue ' the result was ' . $m->result . ' <br />'
// Append the match to a file
$fp = fopen('allmatches.csv', 'a');
fputcsv($fp, $m->getAll());
fclose($fp);
?>
This uses fputcsv to format the array into a line in the csv format. Having a method or some way to create a match from an array is left as an exercise. You possibly have a static method taking a file name as a parameter, and return an array of matches.
There is no good or bad model when you aren't trying to solve a well-defined problem just like there's no good answer to a bad question.
Before even worrying about things such as getters and setters you need to determine the purpose of the model and what problem it is trying to solve.
I understand that this is probably just a modeling exercise, but if you want it to have any value, start by defining your problem domain and then work out the solution.
For instance, if you are modeling an application service that allows to query a list of matches, then perhaps Match is a simple immutable data structure that acts as a Data Transfer Object.
If you were modeling a ViewModel that is meant to be 2-way bound to a CRUD screen allowing to update the details of a Match then perhaps you'd have a data container with public getters and setters like you had.
If you were crafting a tournament system domain model and had a use case such as: "Tournament administrators will enter the scoring of a match after it's completion. The outcome will be automatically resolved by the system. The possible results are that the home/away team wins or a draw."
Then perhaps Match would carry a behavior such as (pseudo-code):
scoring = new Scoring(homeTeamScore: 2, awayTeamScore: 3);
match.complete(scoring);
match.outcome(); //-> MatchOutcome.AwayTeamWon
As you can see, the model should be a solution to a well-defined problem. It should model the reality of that problem (not the real world), no more, no less.
I would like to use the rand() function for match ID can I do this
inside the setter function of setMatchId or should it be done outside
of the class?
The generation of an entity's identity is usually not the responsibility of the identity itself in respect to the Single Responsibility Principle. The algorithm that generates the identity may change independently of the Match concept itself.
First of all, there's nothing bad in having several get/set methods, unless you're coding on a 64kb RAM machine (Where you probably would use C, Lua, or such instead of PHP). If they're all doing (almost) the same thing and you think they're messing code up, put them on the very end of your class, so they don't block your vision ;-).
For the practical altering of your code:
If you have several members which differ only by data but actually represent the same kind, like team1, team2 puting them into an array and use a get/setByIndex is legit.
(Take care: I didn't use PHP for hundreds of years or so, there might me syntactical mistakes)
Example:
function setTeamByIndex($pIndex, $pTeam){
$this->teams[$pIndex] = $pTeam;
}
function getTeamByIndex($pIndex){
return $this->team[$pIndex];
}
Alternatively, in other language it's common to return multiple values. This is not possible in PHP, but there's a workaround:
setTeamsFromArray
-- receives an Array with teams and applies the given teams by their key.
getAllTeamsArray
-- returns an Array, containing all teams.
function setTeamsFromArray($pTeams){
foreach ($pTeams as $key=>$team) {
$this->teams[$key] = $team
}
}
function getAllTeamsArray(){
return array( $this->team1, $this->team2 )
}
echo(getAllTeamsArray()[0]) -> echos team1
echo(getAllTeamsArray()[1]) -> echos team2
In my opinion, this is all one reasonable could do in your case.
Shrinking stuff down is not always reasonable and 10 4liners are, most of the time, better than 1 40liner.
for geter and seter you can use __call() magic method for example realize the geters and setters
public function __call($name, $arguments)
{
// TODO: Implement __call() method.
$method = substr($name,0,3);
$key = strtolower(substr($name,3,strlen($name)));
if($method == 'set') {
$this->_data[$key] = $argument[0]
return $this;
} elseif($method=='get') {
if(isset($this->_data[$key])) {
return $this->_data[$key];
} else {
return null;
}
}
}
this is simple realization getter and setter automaticaly generate.

Is it a bad practice to define class options through an array?

When we take a look at Javascript frameworks like Dojo, Mootools, jQuery, JS Prototype, etc. we see that options are often defined through an array like this:
dosomething('mainsetting',{duration:3,allowothers:true,astring:'hello'});
Is it a bad practice to implement the same idea when writing a PHP class?
An example:
class Hello {
private $message = '';
private $person = '';
public function __construct($options) {
if(isset($options['message'])) $this->message = $message;
if(isset($options['person'])) $this->person = $person;
}
public function talk() {
echo $this->person . ' says: ' . $this->message;
}
}
The regular approach:
class Hello {
private $message = '';
private $person = '';
public function __construct() {}
public function setmessage($message) {
$this->message = $message;
}
public function setperson($person) {
$this->person = $person;
}
public function talk() {
echo $this->person . ' says: ' . $this->message;
}
}
The advantage in the first example is that you can pass as much options as you want and the class will only extract those that it needs.
For example, this could be handy when extracting options from a JSON file:
$options = json_decode($options);
$hello = new Hello($options);
This is how I do this regulary:
$options = json_decode($options);
$hello = new Hello();
if(isset($options['message'])) $hello->setmessage($options['message']);
if(isset($options['person'])) $hello->setperson($options['person']);
Is there a name for this pattern and do you think this is a bad practice?
I have left validation etc. in the examples to keep it simple.
There are good and bad aspects.
The good:
No need for multiple method signatures (i.e. overloading, where supported)
In keeping with the previous point: methods can be invoked with arguments in any order
Arguments can be dynamically generated, without needing to specify each one that will be present (example: you dynamically create an array of arguments based on user input and pass it to the function)
No need for "boilerplate" methods like setName, setThis, setThat, etc., although you might still want to include them
Default values can be defined in the function body, instead of the signature (jQuery uses this pattern a lot. They frequently $.extend the options passed to a method with an array of default values. In your case, you would use array_merge())
The bad:
Unless you properly advertise every option, your class might be harder to use because few will know what options are supported
It's one more step to create an array of arguments when you know ahead of time which you will need to pass
It's not always obvious to the user that default values exist, unless documentation is provided or they have access to the source code
In my opinion, it's a great technique. My favorite aspect is that you don't need to provide overloaded methods with different signatures, and that the signature isn't set in stone.
There's nothing wrong with that approach, especially if you have a lot of parameters you need to pass to a constructor. This also allows you to set default values for them and array_merge() them inside a constructor (kinda like all jQuery plugins do)
protected $default_params = array(
'option1' => 'default_value'
);
public function __construct($params = array()) {
$this->params = array_merge($this->default_params, $params);
}
If you want live examples of this "pattern", check out symfony framework, they use it almost every where: here's an example of sfValidatorBase constructor
When you give the arguments names it's called "Named Notation" v.s. "Positional Notation" where the arguments must be in a specific order.
In PHP you can pass an "options" parameter to give the same effect as other languages (like Python) where you can use a genuine Named Notation. It is not a bad practice, but is often done where there is a good reason to do it (i.e. in your example or a case where there are lots of arguments and they do not all need to set in any particular order).
I don't know the name, but i really doubt it is a bad practice, since you usally use this when you wan't to declare a small o quick function or class property
If there are mandatory options, they should be in the constructor's parameter list. Then you add the optional options with default values.
public function __construc($mandatory1, $mandatory2, $optional1="value", $optional2="value") { }
If all of your options are optional, then it can be useful to create a constructor taking an array. It would be easier to create the object than with a "normal constructor" : you could provide just the options you want, while with a "normal constructor" if you want to provide $optional2, you have to provide $optional1 (even setting it to the default value).
I wouldn't say its bad practice, at least if you trust the source of the data.
Another possibility would be dynamically calling the setters according to the options array key, like the following:
public function __construct($options) {
foreach($options as $option => $value) {
$method = 'set'.$option;
if(method_exists($this, $method)
call_user_func(array($this, $method, $value);
}
}
Why not do both? Have your constructor cake and eat it too with a static factory "named constructor":
$newHello = Hello::createFromArray($options);
You first have your constructor with the options in order. Then add a static method like this to the same class:
public static function createFromArray($options){
$a = isset($options['a']) ? $options['a'] : NULL;
$b = isset($options['b']) ? $options['b'] : NULL;
$c = isset($options['c']) ? $options['c'] : NULL;
return new Hello($a, $b, $c);
}
This will keep new developers and IDE's happy as they can still see what it takes to construct your object.
I agree with the general attitude of the answers here in that either way is a viable solution depending on your needs and which is more beneficial for your app.

PHP: Passing functions to a class

I made a class. I give it some objects (mostly retreived database rows) as input, and tell it which fields it has to show, and which buttons I want. Then it renders a very nice html table! It's pretty awesome, I think.
$ot = new ObjectTable();
$ot->objects = $some_objects;
$ot->fields = array('id','name','description','image');
$ot->buttons = array('edit','delete');
$ot->render();
However, I also want to be able to manipulate the data it shows. For example, i want to be able to truncate the 'description' field. Or to display an image thumbnail (instead of 'picture.jpg' as text). I don't know how to pass these functions to the class. Perhaps something like:
$ot->functions = array(null,null,'truncate','thumbnail');
But then I don't know how to convert these strings to run some actual code, or how to pass parameters.
There must be a nice way to do what I want. How?
Check this question and the answer is:
As of PHP5.3 you could use closures
or functors to pass methods
around. Prior to that, you could write
an anonymous function with
create_function(), but that is
rather awkward.
But what you are trying to achieve is best solved by passing Filter Objects to your renderer though. All filters should use the same method, so you can use it in a Strategy Pattern way, e.g. write an interface first:
interface Filter
{
public function filter($value);
}
Then write your filters implementing the interface
class TruncateFilter implements Filter
{
protected $_maxLength;
public function __construct($maxLength = 50)
{
$this->_maxLength = (int) $maxLength;
}
public function filter($value)
{
return substr(0, $this->_maxLength, $value) . '…';
}
}
Give your ObjectTable a method to accept filters
public function addFilter($field, Filter $filter)
{
if(in_array($field, $this->fields)) {
$this->_filters[$field][] = $filter;
}
return $this;
}
And when you do your ObjectTable instantiation, use
$ot = new ObjectTable();
$ot->objects = $some_objects;
$ot->fields = array('id','name','description','image');
$ot->addFilter('description', new TruncateFilter)
->addFilter('name', new TruncateFilter(10))
->addFilter('image', new ThumbnailFilter);
Then modify your render() method to check if there is any Filters set for the fields you are rendering and call the filter() method on them.
public function render()
{
foreach($this->fields as $field) {
$fieldValue = // get field value somehow
if(isset($this->filters[$field])) {
foreach($this->filters[$field] as $filter) {
$fieldValue = $filter->filter($fieldValue)
}
}
// render filtered value
}
}
This way you can add infinite filters.
PHP has a pseudo-type called "callback", which is actually an ugly closure in disguise. You can call such callbacks using call_user_func() or call_user_func_array():
$callback = 'strlen';
echo call_user_func($callback, '123');
// will output 3 (unless you're using a strange encoding)
You are looking for create_function().
However, creating functions on runtime and adding them to a class doesn't sound right to me. It's likely to become a maintenance nightmare very quickly. There are better ways to achieve what you want. What kind of manipulation would the functions to to the data? How about storing them in a "tools" class and connecting that with the table object when needed?
$functions = array(null,null,'truncate','thumbnail');
$function_1 = $functions[3];
$my_string = 'string to truncate';
$result = call_user_func($functions[2], $my_string);
If you want to pass multiple parameters, use call_user_func_array instead.
You might also want to explore call_user_func, which allows you to call a function based on a string representing its name.

How to call a function from a string stored in a variable?

I need to be able to call a function, but the function name is stored in a variable, is this possible? e.g:
function foo ()
{
//code here
}
function bar ()
{
//code here
}
$functionName = "foo";
// I need to call the function based on what is $functionName
$functionName() or call_user_func($functionName)
My favorite version is the inline version:
${"variableName"} = 12;
$className->{"propertyName"};
$className->{"methodName"}();
StaticClass::${"propertyName"};
StaticClass::{"methodName"}();
You can place variables or expressions inside the brackets too!
Solution: Use PHP7
Note: For a summarized version, see TL;DR at the end of the answer.
Old Methods
Update: One of the old methods explained here has been removed. Refer to other answers for explanation on other methods, it isn't covered here. By the way, if this answer doesn't help you, you should return upgrading your stuff. PHP 5.6 support has ended in January 2019 (now even PHP 7.2 and 7.3 are not being supported). See supported versions for more information.
As others mentioned, in PHP5 (and also in newer versions like PHP7) we could use variables as function names, use call_user_func() and call_user_func_array(), etc.
New Methods
As of PHP7, there are new ways introduced:
Note: Everything inside <something> brackets means one or more expressions to form something, e.g. <function_name> means expressions forming a function name.
Dynamic Function Call: Function Name On-the-fly
We can form a function name inside parentheses in just one go:
(<function_name>)(arguments);
For example:
function something(): string
{
return "something";
}
$bar = "some_thing";
(str_replace("_", "", $bar))(); // something
// Possible, too; but generally, not recommended, because makes your
// code more complicated
(str_replace("_", "", $bar))()();
Note: Although removing the parentheses around str_replace() is not an error, putting parentheses makes code more readable. However, you cannot do that sometimes, e.g. while using . operator. To be consistent, I recommend you to put the parentheses always.
Dynamic Function Call: Callable Property
A useful example would be in the context of objects: If you have stored a callable in a property, you have to call it this way:
($object->{<property_name>})();
As a simple example:
// Suppose we're in a class method context
($this->eventHandler)();
Obviously, calling it as $this->eventHandler() is plain wrong: By that you mean calling a method named eventHandler.
Dynamic Method Call: Method Name On-the-fly
Just like dynamic function calls, we can do the same way with method calls, surrounded by curly braces instead of parentheses (for extra forms, navigate to TL;DR section):
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
See it in an example:
class Foo
{
public function another(): string
{
return "something";
}
}
$bar = "another thing";
(new Something())->{explode(" ", $bar)[0]}(); // something
Dynamic Method Call: The Array Syntax
A more elegant way added in PHP7 is the following:
[<object>, <method_name>](arguments);
[<class_name>, <method_name>](arguments); // Static calls only
As an example:
class Foo
{
public function nonStaticCall()
{
echo "Non-static call";
}
public static function staticCall()
{
echo "Static call";
}
}
$x = new X();
[$x, "non" . "StaticCall"](); // Non-static call
[$x, "static" . "Call"](); // Static call
Note: The benefit of using this method over the previous one is that, you don't care about the call type (i.e. whether it's static or not).
Note: If you care about performance (and micro-optimizations), don't use this method. As I tested, this method is really slower than other methods (more than 10 times).
Extra Example: Using Anonymous Classes
Making things a bit complicated, you could use a combination of anonymous classes and the features above:
$bar = "SomeThing";
echo (new class {
public function something()
{
return 512;
}
})->{strtolower($bar)}(); // 512
TL;DR (Conclusion)
Generally, in PHP7, using the following forms are all possible:
// Everything inside `<something>` brackets means one or more expressions
// to form something
// Dynamic function call via function name
(<function_name>)(arguments);
// Dynamic function call on a callable property
($object->{<property_name>})(arguments);
// Dynamic method call on an object
$object->{<method_name>}(arguments);
$object::{<method_name>}(arguments);
// Dynamic method call on a dynamically-generated object
(<object>)->{<method_name>}(arguments);
(<object>)::{<method_name>}(arguments);
// Dynamic method call, statically
ClassName::{<method_name>}(arguments);
(<class_name>)::{<method_name>}(arguments);
// Dynamic method call, array-like (no different between static
// and non-static calls
[<object>, <method_name>](arguments);
// Dynamic method call, array-like, statically
[<class_name>, <method_name>](arguments);
Special thanks to this PHP talk.
Yes, it is possible:
function foo($msg) {
echo $msg."<br />";
}
$var1 = "foo";
$var1("testing 1,2,3");
Source: http://www.onlamp.com/pub/a/php/2001/05/17/php_foundations.html?page=2
As already mentioned, there are a few ways to achieve this with possibly the safest method being call_user_func() or if you must you can also go down the route of $function_name(). It is possible to pass arguments using both of these methods as so
$function_name = 'foobar';
$function_name(arg1, arg2);
call_user_func_array($function_name, array(arg1, arg2));
If the function you are calling belongs to an object you can still use either of these
$object->$function_name(arg1, arg2);
call_user_func_array(array($object, $function_name), array(arg1, arg2));
However if you are going to use the $function_name() method it may be a good idea to test for the existence of the function if the name is in any way dynamic
if(method_exists($object, $function_name))
{
$object->$function_name(arg1, arg2);
}
A few years late, but this is the best manner now imho:
$x = (new ReflectionFunction("foo"))->getClosure();
$x();
In case someone else is brought here by google because they were trying to use a variable for a method within a class, the below is a code sample which will actually work. None of the above worked for my situation. The key difference is the & in the declaration of $c = & new... and &$c being passed in call_user_func.
My specific case is when implementing someone's code having to do with colors and two member methods lighten() and darken() from the csscolor.php class. For whatever reason, I wanted to have the same code be able to call lighten or darken rather than select it out with logic. This may be the result of my stubbornness to not just use if-else or to change the code calling this method.
$lightdark="lighten"; // or optionally can be darken
$color="fcc"; // a hex color
$percent=0.15;
include_once("csscolor.php");
$c = & new CSS_Color($color);
$rtn=call_user_func( array(&$c,$lightdark),$color,$percent);
Note that trying anything with $c->{...} didn't work. Upon perusing the reader-contributed content at the bottom of php.net's page on call_user_func, I was able to piece together the above. Also, note that $params as an array didn't work for me:
// This doesn't work:
$params=Array($color,$percent);
$rtn=call_user_func( array(&$c,$lightdark),$params);
This above attempt would give a warning about the method expecting a 2nd argument (percent).
For the sake of completeness, you can also use eval():
$functionName = "foo()";
eval($functionName);
However, call_user_func() is the proper way.
Dynamic function names and namespaces
Just to add a point about dynamic function names when using namespaces.
If you're using namespaces, the following won't work except if your function is in the global namespace:
namespace greetings;
function hello()
{
// do something
}
$myvar = "hello";
$myvar(); // interpreted as "\hello();"
What to do?
You have to use call_user_func() instead:
// if hello() is in the current namespace
call_user_func(__NAMESPACE__.'\\'.$myvar);
// if hello() is in another namespace
call_user_func('mynamespace\\'.$myvar);
Complementing the answer of #Chris K if you want to call an object's method, you can call it using a single variable with the help of a closure:
function get_method($object, $method){
return function() use($object, $method){
$args = func_get_args();
return call_user_func_array(array($object, $method), $args);
};
}
class test{
function echo_this($text){
echo $text;
}
}
$test = new test();
$echo = get_method($test, 'echo_this');
$echo('Hello'); //Output is "Hello"
I posted another example here
Use the call_user_func function.
What I learnt from this question and the answers. Thanks all!
Let say I have these variables and functions:
$functionName1 = "sayHello";
$functionName2 = "sayHelloTo";
$functionName3 = "saySomethingTo";
$friend = "John";
$datas = array(
"something"=>"how are you?",
"to"=>"Sarah"
);
function sayHello()
{
echo "Hello!";
}
function sayHelloTo($to)
{
echo "Dear $to, hello!";
}
function saySomethingTo($something, $to)
{
echo "Dear $to, $something";
}
To call function without arguments
// Calling sayHello()
call_user_func($functionName1);
Hello!
To call function with 1 argument
// Calling sayHelloTo("John")
call_user_func($functionName2, $friend);
Dear John, hello!
To call function with 1 or more arguments
This will be useful if you are dynamically calling your functions and each function have different number of arguments. This is my case that I have been looking for (and solved). call_user_func_array is the key
// You can add your arguments
// 1. statically by hard-code,
$arguments[0] = "how are you?"; // my $something
$arguments[1] = "Sarah"; // my $to
// 2. OR dynamically using foreach
$arguments = NULL;
foreach($datas as $data)
{
$arguments[] = $data;
}
// Calling saySomethingTo("how are you?", "Sarah")
call_user_func_array($functionName3, $arguments);
Dear Sarah, how are you?
Yay bye!
If you were in a object context trying to call a function dynamically please try something like this code bellow:
$this->{$variable}();
The easiest way to call a function safely using the name stored in a variable is,
//I want to call method deploy that is stored in functionname
$functionname = 'deploy';
$retVal = {$functionname}('parameters');
I have used like below to create migration tables in Laravel dynamically,
foreach(App\Test::$columns as $name => $column){
$table->{$column[0]}($name);
}
Following code can help to write dynamic function in PHP.
now the function name can be dynamically change by variable '$current_page'.
$current_page = 'home_page';
$function = #${$current_page . '_page_versions'};
$function = function() {
echo 'current page';
};
$function();
Considering some of the excellent answers given here, sometimes you need to be precise.
For example.
if a function has a return value eg (boolean,array,string,int,float
e.t.c).
if the function has no return value check
if the function exists
Let's look at its credit to some of the answers given.
Class Cars{
function carMake(){
return 'Toyota';
}
function carMakeYear(){
return 2020;
}
function estimatedPriceInDollar{
return 1500.89;
}
function colorList(){
return array("Black","Gold","Silver","Blue");
}
function carUsage(){
return array("Private","Commercial","Government");
}
function getCar(){
echo "Toyota Venza 2020 model private estimated price is 1500 USD";
}
}
We want to check if method exists and call it dynamically.
$method = "color List";
$class = new Cars();
//If the function have return value;
$arrayColor = method_exists($class, str_replace(' ', "", $method)) ? call_user_func(array($this, $obj)) : [];
//If the function have no return value e.g echo,die,print e.t.c
$method = "get Car";
if(method_exists($class, str_replace(' ', "", $method))){
call_user_func(array($class, $method))
}
Thanks
One unconventional approach, that came to my mind is, unless you are generating the whole code through some super ultra autonomous AI which writes itself, there are high chances that the functions which you want to "dynamically" call, are already defined in your code base. So why not just check for the string and do the infamous ifelse dance to summon the ...you get my point.
eg.
if($functionName == 'foo'){
foo();
} else if($functionName == 'bar'){
bar();
}
Even switch-case can be used if you don't like the bland taste of ifelse ladder.
I understand that there are cases where the "dynamically calling the function" would be an absolute necessity (Like some recursive logic which modifies itself). But most of the everyday trivial use-cases can just be dodged.
It weeds out a lot of uncertainty from your application, while giving you a chance to execute a fallback function if the string doesn't match any of the available functions' definition. IMHO.
I dont know why u have to use that, doesnt sound so good to me at all, but if there are only a small amount of functions, you could use a if/elseif construct.
I dont know if a direct solution is possible.
something like
$foo = "bar";
$test = "foo";
echo $$test;
should return bar, you can try around but i dont think this will work for functions

Categories