I am currently working on a project on the Codeigniter MVC framework. I have created an authentication library to suite the project with several functions. I will be checking and validating data in my controller and then passing the data into one of these functions. For example my register function takes about 5 parameters at the moment, but should I pass these in as strings or should I pass them in as an array? Is there a set rule or is this personal preference?
It's personal preference. If you are passing the parameters to a function, it can be easier to pass them in an array if there are quite a few parameters. Also, passing the parameters in an array means you don't have to pass them to a function in a specific order as you must do when passing each parameter to a function individually.
Example...
function myFunc($param1, $param2, $param3, $param4, $param5) { ... }
For the above, you must pass all params in the exact order...
myFunc('Something', '', 'Something Else', '', '');
An easier way is to pass the parameters in an array...
function myFunc($array) { ... }
The $array can contain all or some of the parameters in any order...
$array { 'param1' => 'Something', 'param3' => 'Something Else' ... }
You just have to make sure your function addresses missing parameters gracefully if you are passing them via an array...
if (empty($array['param1'])) return false; // or whatever should happen
Well it's up to you, but with an array you have to check yourself that proper indices were set to proper types. With individual parameters (and possibly type hints) php will do this for you. Also individual parameters work better with IDE.
Related
symfony 3.4
I have to call a function
$this->em->getRepository($info['repoName'])->$info['funcName']->(//params
the problem is that my function has parameters by coma like
functionName($param1, $param2);
and I receive an array that has values of this parameters in
$arr['params']
VERY IMPORTANT!
I will not be able to call it like functionName($arr['params'][0], $arr['params'][1]) because I will never know what function from what repo is used and how many params it has, this all info is stored in yml, taken from there, data is just found in other functions and just passed here. Guys please pay attention at this - this is dynamic, there may be any number of params in array and it is of course the same as in function, but how to call the function when parameters should be specified with coma and I have an array?
Depending on your PHP version there are different approaches. I personally prefer argument unpacking, also referred to as splat-operator:
$this->em->getRepository($info['repoName'])->$info['funcName']->(...$info['params']);
This feature was introduced in PHP 5.6, see: https://secure.php.net/manual/en/migration56.new-features.php#migration56.new-features.splat
Another common approach is to use call_user_func_array where you provide a callable for what method should be called on which object and then an array of arguments. In your case it will probably look something like this:
call_user_func_array([$this->em->getRepository($info['repoName']), $info['funcName']], $info['params']);
Try call_user_func_array :
call_user_func_array([
$this->em->getRepository($info['repoName']), $info['funcName']
],
$arr['params']
);
I am looking into building my own custom small framework and trying to make it as flexible as possible, I have now got to the input process of the design and I am wondering how I could implement the "request" class and how to return POST params from a POST request, etc.
I noticed that a lot of frameworks have a request class which hook directly into the "php://input" stream which I have tried to do and would like to utilize, however the only problem is this returns a string instead of an object or array of value=params.
What may be the best way for me to implement a method which would give me access to the param values of a POST request? I could probably explode the "php://input" string however this would be messy, I also tried the parse_str() on the stream which worked however sadly this also has issues if one of those values is something along the lines of foo">bar< as it seems to break out of the object and leave me with a partial incomplete value of foo.
My ultimate solution would be something along the lines of:
$_POST contains foo=bar;arg=value;
class request {
function get($arg=null)(){
if(!arg){/* return all, both foo and arg accessible*/}
else
/*return single value of the param with the $arg text*/
}
$foo = request->get('foo'); // "bar"
$all = request->get() // foo=bar;arg=value;
print $all->arg; // "value"
add_filter('wp_list_pages_excludes', 'gr_wp_list_pages_excludes');
function gr_wp_list_pages_excludes($exclude_array) {
$id_array=$array('22');
$exclude_array=array_merge($id_array, $exclude_array);
return $exclude_array;
}
I'm a newbie to wordpress. The above code works fine. But I need to pass additional argument, say $mu_cust_arg to the function gr_wp_list_pages_excludes. How can I make use of it via apply_filters, or any other methods?
Any help is appreciated.
Thanks in advance.
You can indeed add multiple arguments to a filter/action, you just need to tell WordPress how many arguments to expect
Example, which won't work:
add_filter('some_filter', function($argument_one, $argument_two) {
// won't work
});
apply_filters('some_filter', 'foo', 'bar'); // won't work
It will fail with an error that too many arguments was provided.
Instead, you need to add this:
add_filter('some_filter', function($argument_one, $argument_two) {
// works!
$arugment_one; // foo
$arugment_two; // bar
}, 10, 2); // 2 == amount of arguments expected
apply_filters('some_filter', 'foo', 'bar');
Because WP doesn't accept closures as callbacks (at least, certainly not for add_filter()) the short answer is "you can't". At least, not in a tidy way.
There are a couple of options here, depending on what you are doing. The first is the best, but you may not be able to use it:
Write a wrapper function that calls your function:
function gr_wp_list_pages_excludes_1 ($exclude_array) {
$custom_arg = 'whatever';
gr_wp_list_pages_excludes_1($exclude_array, $custom_arg)
}
This will only work if you are always passing the same custom argument in a given situation - you would write one of these wrapper functions for each different situation, and pass the name of the wrapper function to add_filter(). Alternatively, if you want it to be truly dynamic, you would need to...
Use a global variable: (Ref: Variable scope, $GLOBALS)
function gr_wp_list_pages_excludes($exclude_array) {
global $gr_wp_list_pages_excludes_custom_arg;
$id_array=$array('22');
$exclude_array=array_merge($id_array, $exclude_array);
return $exclude_array;
}
Using this approach means that you can pass any data you like into the function by assigning it to $gr_wp_list_pages_excludes_custom_arg in the global scope. This is generally regarded as bad practice and heavily frowned upon, because it makes for messy and unreadable code and leaves the memory space littered with extra variables. Note that I have made the variable name very long and specific to the function to avoid collisions - another problem with using global variables. While this will work, only use it if you absolutely have to.
Very simple!
add_filter('filter_name','my_func',10,3); //three parameters lets say..
my_func($first,$second,$third){
//............
}
then
echo apply_filters('filter_name',$a,$b,$c);
In the end, I got this function. I don't know whether it's normal or not.
function user_registration($user_name, $user_email, $user_pass, $address,
$city, $postalcode, $country, $phone, $mobilephone)
How and why can I improve this?
You could either pass an array with all variables packed nicely together, or just make a "User" class and add all properties via setters and do the validation in the end with a dedicated method:
class User {
public function setName($name) {
$this->name = $name;
}
[...]
public function register() {
//Validate input
if (empty($this->name))
$this->errors[] = "ERROR, Username must not be emtpy";
//Add the user to the database
//Your SQL query
return empty($this->errors);
}
}
$user = new User();
$user->setName("Peter");
$success = $user->register();
if (!$success)
echo "ERRORS OCCURED: ".print_r($user->errors, true);
A solution would be to only have one parameter, that can contain several pieces of data -- like an array.
Your function could be defined this way :
function user_registration(array $data) {
// work with $data['name']
// and $data['email']
// ...
}
And you'd call it like this :
user_registration(array(
'name' => 'blah',
'email' => 'test#example.com',
'pass' => '123456',
// and so on
));
Nice things are :
You can add / remove "parameters" easily
The "parameters" can be passed in any order you want
Not so bad things are :
No hint while typing in your IDE
No documentation (like phpDoc)
I personally don't think it has too many parameters. From looking at the functions definition it is clear what you require as input which wouldn't be so obvious if called with an array.
"If it aint broke don't fix it!"
When you look at your argument names, you cannot but notice that they can be grouped into three different groups:
User Data: $user_name, $user_pass
Address Data: $address, $city, $postalcode, $country
Contact Data: $user_email, $phone, $mobilephone
Consequently, you could apply Introduce Parameter Object:
Often you see a particular group of parameters that tend to be passed together. Several methods may use this group, either on one class or in several classes. Such a group of classes is a data clump and can be replaced with an object that carries all of this data. It is worthwhile to turn these parameters into objects just to group the data together. This refactoring is useful because it reduces the size of the parameter lists, and long parameter lists are hard to understand. The defined accessors on the new object also make the code more consistent, which again makes it easier to understand and modify.
If you dont want to do OOP you could group the arguments into arrays as well but you'll lose all the type benefits then. I will just assume you don't mind using objects. So, after applying the Refactoring you'll end up with
function user_registration(User $user, Address $address, Contact $contact)
Looking at that parameter list should make you notice that Address and Contact likely belong to User in the first place, so you could consider changing the function signature to just
function user_registration(User $user)
and then call it like this:
$user = new User('johndoe', 'secretsauce');
$user->setAddress(new Address('Doe Street', 'Doe Town', 12345, 'Neverland'));
$user->setContact('jdoe#example.com', '+123 12345', '+123 54321');
user_registration($user);
We could probably make username and password into a Credentials object as well and then just do
user_registration(new User($credentials, $address, $contact));
By requiring the data in the ctor we make sure newly registered users do have all these information. We could argue whether we need Address and Contact for registering users though, so Setter injection might be good enough here:
$user = new User(new Credentials('johndoe', 'secretsauce'));
$user->setAddress(new Address('Doe Street', 'Doe Town', 12345, 'Neverland'));
$user->setContact(new Contact('jdoe#example.com', '+123 12345', '+123 54321'));
user_registration($user);
However, user_registration as a separate function in global scope is misplaced. By GRASP's Information Expert principle, methods should be on the objects that have the most information to fulfill the responsibility. This improves Cohesion and reduces Coupling. In other words:
$user = new User($credentials);
$user->setAddress($address);
$user->setContact($contact);
$user->register();
One problem with the User class now is that it contains the password. The password is only ever needed to authenticate the user against the authentication service. We could argue about the username, but the password definitely should not be part of the User object at all. So you should do something like
$user = new User;
$user->setAddress($address);
$user->setContact($contact);
$user->register($credentials);
and when register() is called, it will only use the credentials to delegate insertion of a new user into the user storage. But it will not retain them in the actual User instance.
Finally, you might want to add a Simple Factory or Builder pattern to encapsulate the creation of the User to simplify the aggregation of the various instances. Or you might want to introduce a Repository pattern and move the register() method there. This is beyond scope for this question though.
As a general rule of thumb (not as a steadfast rule), anytime you have to ask "Does this function have too many parameters?" -- the answer is yes. Your intuition is telling you something that your brain just hasn't yet been able to work out.
In this particular case, the first thing that comes to mind is that your user cred.s should be checked first (does the username already exist? is the pw complex enough) and your user details should be added separately, probably using an object or array.
One way is to pass an array as parameter to this function and put all info in that array:
function user_registration(array $user_info)
{
// process $user_info;
}
Function (method) without any parameters is best. Function with one paremeter is better than function with 2 parameters. Function with 2 parameters is better than function with 3 parameters and so on.
#Florianh has given a perfect solution how your code can be improved. With this comment, I would like to elaborate on the "why" part from a system design perspective.
From an Object Oriented perspective, other objects should be able to manipulate attributes. That is why attributes should never be defined as "public". They should be "private" e.g.:
private var $name;
The reason for this is when other objects would manipulate this variable, the correct working of the object is at risk. Methods, on the other hand, can be defined publicly:
public function register()
Accordingly, the manipulation of the attributes will happen through the appropriate methods. A method can be used to also evaluate the correctness of operations on the attributes.
There are two operations that can happen: reading the current value of an attribute by using Get methods and saving a new value of an attribute by using Set methods.
A good practice would be to implement a get method for each class attribute. Each attribute that can be modified, should have an appropriate set method as well.
Sometimes it is better to not implement a get/set method (e.g.: showData()) after all. This is because the usage of getters and setters within a particular class may possibly lead to a reduced performance. However, this means that when changing or implementing the class, one must be careful when trying to save false information and as a result putting the integrity of the class at risk.
Now, consider the fact that you decide to use only one phone number instead of both a phone- and mobile number. When the mobile number becomes deprecated, your main program still remains the same. All you have to do is change/remove one method. The advantage of using getters and setters is an increase in adaptability and maintainability.
I make array of keys like
$fields = array('field1', 'field2');
function register (array $values, array $keys)
{
$data = array();
foreach ($keys as $one)
{
if (isset($values[$one])) $data[$one] = $values[$one];
}
// or you can use array functions like array_flip and after - array intersect
}
I'd make it this way
fields=explode(",","name,surname,lastname,street,city,region,zip,country");
user_registration($fields);
Because I am sure these variables coming from $_POST
I'm writing a construct in PHP where a parser determins which function to call dynamically, kind of like this:
// The definition of what to call
$function_call_spec = array( "prototype" => "myFunction",
"parameters" => array( "first_par" => "Hello",
"second_par" => "World"));
// Dispatch
$funcPrototype = $function_call_spec["prototype"];
$funcPrototype(); // Here we call function 'myFunction'.
This is all fine and dandy. But now comes the next step, passing the parameters, which I don't really know if it's possible the way I want to do it. It never stops amazing me however what script languages can do these days, so here goes:
One could pass the parameters to the function like this:
// Here we call function 'myFunction' with the array of parameters.
$funcPrototype( $function_call_spec["parameters"] );
However, I want to declare 'myFunction' properly with clear arguments etc:
function myFunction( $first_par, $second_par )
{
}
The question then follows - Is there any way to pass parameters to a function dynamically simply by looping through the parameter array?
To clarify, I don't want to do it like this:
$funcPrototype( $function_call_spec["parameters"]["first_par"],
$function_call_spec["parameters"]["second_par"] );
Because this requires my code to statically know details about myFunction, which goes against the whole idea.
Instead I would want to do it in some way like this maybe:
// Special magic PHP function which can be used for invoking functions dynamically
InvokeFunction( $funcPrototype, $function_call_spec["parameters"] );
Which then results in myFunction being called and all parameters in the array gets passed to each individual parameter variable in the prototype.
Any comments are welcome.
Regards.
/R
PS: None of the code in this post has been tested for typos etc.
You should use call_user_func_array which can call any function or method and takes parameteres from an array.
Alternatively you can use ReflectionFunction::invokeArgs, but there's no benefit over call_user_func_array unless you already use this class for someting else (like checking whether function you call accepts appropriate number and types of arguments).
call_user_func_array($funcPrototype, $function_call_spec["parameters"]);
You might want to create a wrapper that names the function to your preference, such as:
function InvokeFunction($function, $args = array()) {
return call_user_func_array($function, (array)$args);
}
With this function you can call it in 3 different ways:
$return = InvokeFunction('doStuff');
$return = InvokeFunction('doStuff', $single_arg);
$return = InvokeFunction('doStuff', $multiple_args);
call_user_func_array() is the best choice if you don't need to enforce the contract, otherwise use ReflectionFunction.
http://us2.php.net/create_function
When you use create_function(), your arguments are not evaluated until runtime. Pretty sweet.