When i write down a function is a good practice to validate all the parameters of the function like this:
<?php
/**
* foo - Test function
*
* #param int $paramA
* #param str $paramB
* #param array $paramC
*
* #return something
*/
function foo($paramA, $paramB, $paramC) {
// verify all parameters
if(!is_int($paramA)) {
return 0; // or error msg
}
if(!is_string($paramB)) {
return 1; // or error msg
}
if(!is_array($paramC)) {
return 2; // or error msg
}
// some code in function scope that uses parameters
// and saves the results in $result
return $result;
}
or should i rely on the user that will use the function and assume that he knows what he is doing and forget about parameter validation?
Personally i prefer to validate all the parameter of the function and return error codes for consistency of the code and make my life easier afterwords.
Thank you in advance.
I think the answer is: it depends
It depends on who you are writing your code for. If you're looking for the most generalized answer, then yes, you should.
If your script will only ever be used by you and you know in your heart of hearts that you will always use it correctly, then you will (probably) be safe if you don't.
If your script is part of an API that will be distributed to many, many people, then you most definitely want to add error checking and provide good fall back error messages for people.
If you are part of a small team that will all be using the same code, I would also suggest that validating your arguments according to your particular context would be a good idea.
If it is an internal function that only you will be using, it is probably okay to not validate every single parameter like that. If it is a function that has parameters that depend on user input (for example, you get information through $_GET, and then pass that to a function), then it needs to be validated.
Never rely on a user or anyone else besides yourself to know what they are doing. Sometimes it can be helpful to validate things like this if you are writing code that you can re-use later (like if you were writing your own framework to use across all of your PHP projects). But if it is just one application-specific function that only you can call with parameters that only you define, I wouldn't worry about it.
Why validate your parameters:
Sometimes we really need a certain datatype for an operation. If you give me a string that is not representative of an integer and you use that as a search for a primary key in a database (usually an int), then you will have trouble.
It makes fixing your code easier. When you are checking parameters, you can throw individual exceptions and give messages that are very descriptive. This makes it easier to fix your code when something breaks, because you know exactly what went wrong.
Some tips on type checking:
In case you didn't know, is_int is pretty faulty. I think a valid check to see if it is an int is is_numeric($int) && $int==(int)$int.
You can specify types for objects and arrays, like so: function foo($paramA, $paramB, array $paramC).
Really depends on the type-strictness of what you're doing with those parameters.
Since PHP is weakly typed, you can get away with a lot by casting or just letting the implicit type conversion/coercion do it's thing.
And if you're just going to throw a bunch of guard conditions at the head of every function only to return errors, that's really not much different than PHP triggering errors of its own.
I beg to differ. I recently stumbled upon an article about a similar issue (null checks), but it seems to apply for type checking in php as well. I agree with the author.
Write code in a way that makes type checking redundant.
explicitly validate user input and cast the values to the required types as soon as possible.
In some exceptional cases, you can and should use exceptions instead of returning some obscure error numbers.
It is a very good practice to validate function arguments. I suspect you ask this question because on the other hand it makes your functions look longer and uglier. However with args module from NSPL, it is very easy to do. The function from your example will be:
function foo($paramA, $paramB, array $paramC)
{
expects(int, $paramA);
expects(string, $paramB);
// do something
}
// or type check several arguments
function sum($x, $y)
{
expectsAll(numeric, [$x, $y]);
return $x + $y;
}
More examples here.
Related
I like creating my PHP functions using key=>value pairs (arrays) as arguments instead of individual parameters.
For example, I prefer:
function useless_func($params) {
if (!isset($params['text'])) { $params['text'] = "default text"; }
if (!isset($params['text2'])) { $params['text2'] = "default text2"; }
if (!isset($params['text3'])) { $params['text3'] = "default text3"; }
echo $params['text'].$params['text2'].$params['text3'];
return;
}
And I don't like:
function useless_func($text = "default text", $text2 = "default text2", $text3 = "default text3") {
echo $text.$text2.$text3;
return;
}
I had first seen things done this way extensively in the Wordpress codebase.
The reason I prefer arrays:
Function arguments can be provided in any order
Easier to read code / more self documenting (in my opinion)
Less prone to errors, because when calling a function I must investigate the proper array keys
I was discussing this with a co-worker and he says that it's useless and just leads to extra code and it's much harder to set the default values. Basically, he disagrees with me completely on all three points.
I am looking for some general advise and guidance from experts who might be able to provide insight: What's the better or more proper way to do this?
Don't do that!
Passing all in an array is a bad idea most of the time.
It prevents people from using your function without knowing what it needs to operate.
It lets you create functions needing lots of parameters when probably you should create a function with more precise argument needs and a narrower goal
It seems like the contrary of injecting in a function what it needs.
Function arguments can be provided in any order
I have no such preference. I don't understand that need.
Easier to read code / more self documenting (in my opinion)
Most IDEs will present you with the different arguments a function needs. If one sees a function declaration like foo(Someclass $class, array $params, $id) it is very clear what the function needs. I disagree that a single param argument is easier to read or self documenting.
Less prone to errors, because when calling a function I must investigate the proper array keys
Allowing people to pass in an array without knowing that values will be defaulted is not close to "not error-prone". Making it mandatory for people to read your function before using it is a sure way for it never to be used. Stating that it needs three arguments along with their defaults is less error prone because people calling your function will know which values the parameters will be defaulted to, and trust that it will present the result they expect.
If the problem you are trying to solve is a too great number of arguments, the right decision is to refactor your functions into smaller ones, not hide function dependencies behind an array.
Well, it's kinda usefully. But for some arguments which is passing always it's better to use classic passing like function some($a1, $a2). I'm doing like this in my code:
function getSome(SomeClass $object, array $options = array())
{
// $object is required to be an instance of SomeClass, and there's no need to get element by key, then check if it's an object and it's an instance of SomeClass
// Set defaults for all passed options
$options = array_merge(array(
'property1' => 'default1',
'property2' => 'default2',
... => ...
), $options);
}
So, as you can see I like that code style too, but for core-arguments I prefer classic style, because that way PHP controls more things which should I, if I used the you code style.
I'm assuming you're asking whether it's A Good Thing to write all functions so that they accept only one argument, and for that argument to be an array?
If you're the only person who's ever going to work on your code then you can do what you like. However, by passing all argument values through an array, anyone else is going to have to work harder to understand what the function does and why / how they could use it, especially if they're using an IDE with auto-complete for function names etc. They don't call it a "function signature" for nothing.
I'd recommend that array parameters are reserved either for items where you don't know how many there will be (e.g. a series of data items), or for groups of related options / settings (which may be what's going on in the Wordpress example that you mention?).
If you do continue with a blanket approach to array arguments then you should at least be aware of its impact on readability and take some steps to counter that issue.
Your co-worker is right. Not only is it more code for the same functionality, it is harder to read and probably has lowered performance (Since you need to call isset for each param and you need to access an array to set values).
This borders on Cargo Cult programming. You say this is more readable and self-documenting. I would ask how? To know how to use your function/method I have to read into the code itself. There's no way I can know how to use it from the signature itself. If you use any half-decent IDE or editor that supports method signature hinting this will be a real PITA. Plus you won't be able to use PHP's type-hinting syntax.
If you find you are coding a load of parameters, especially optional parameters then it suggests there might be something wrong with your design. Consider how else you might go about it. If some or all of the parameters are related then maybe they belong to their own class.
Using array_merge() works okay, but using the + operator can be used too; it works the other way, it only adds default values where one hasn't been given yet.
function useless_func(array $params = array())
{
$params += array(
'text' => 'default text',
'text2' => 'default text2',
'text3' => 'default text3',
);
}
See also: Function Passing array to defined key
A few things you don't get with using arrays as function arguments is:
type checking (only applicable to objects and arrays, but it can be useful and in some cases expected).
smart(er) text editors have a code insight feature that will show the arguments a function understands; using arrays takes away that feature, though you could add the possible keys in the function docblock.
due to #2 it actually becomes more error prone, because you might mistype the array key.
Your co-worker is crazy. It's perfectly acceptable to pass in an array as a function argument. It's prevalent in many open source applications including Symfony and Doctrine. I've always followed the 2 argument rule, if a function needs more than two arguments, OR you think it will use more than two arguments in the future, use an array. IMO this allows for the most flexibility and reduces any calling code defects which may arise if an argument is passed incorrectly.
Sure it takes a little bit more work to extrapolate the values from the array, and you do have to account for required elements, but it does make adding features much easier, and is far better than passing 13 arguments to the function every time it needs to be called.
Here is a snippet of code displaying the required vs optional params just to give you an idea:
// Class will tokenize a string based on params
public static function tokenize(array $params)
{
// Validate required elements
if (!array_key_exists('value', $params)) {
throw new Exception(sprintf('Invalid $value: %s', serialize($params)));
}
// Localize optional elements
$value = $params['value'];
$separator = (array_key_exists('separator', $params)) ? $params['separator'] : '-';
$urlEncode = (array_key_exists('urlEncode', $params)) ? $params['urlEncode'] : false;
$allowedChars = (array_key_exists('allowedChars', $params)) ? $params['allowedChars'] : array();
$charsToRemove = (array_key_exists('charsToRemove', $params)) ? $params['charsToRemove'] : array();
....
I have used arrays to substitute a long list of parameters in many occasions and it has worked well. I agree with those in this post that have mentioned about code editors not being able to provide hints for the arguments. Problem is that if I have 10 arguments, and the first 9 are blank/null it just becomes unwieldy when calling that function.
I would also be interested in hearing an how to re-design a function that requires a lot of arguments. For example, when we have a function that builds SQL statements based on certain arguments being set:
function ($a1, $a2, ... $a10){
if($a1 == "Y"){$clause_1 = " something = ".$a1." AND ";}
...
if($a10 == "Y"){$clause_10 = " something_else = ".$a10." AND ";}
$sql = "
SELECT * FROM some_table
WHERE
".$clause_1."
....
".$clause_10."
some_column = 'N'
";
return $sql;
}
I would like to see PHP entertain adding a native helper function that could be used within a the function being called that would assist in passing an array of parameters by undertaking the necessary type checking. PHP recognized this to a certain extent by creating the func_get_args() function which allows arguments to be passed in any order. BUT this will only pass a COPY of the values, so if you want to pass objects to the function this will be a problem. If such a function existed, then the code editors would be able to pick this up and provide details on possible arguments.
#Mike, you could also "extract()" your $params argument into local variables, like this:
// Class will tokenize a string based on params
public static function tokenize(array $params)
{
extract($params);
// Validate required elements
if (!isset($value)) {
throw new Exception(sprintf('Invalid $value: %s', serialize($params)));
}
// Localize optional elements
$value = isset($value) ? $value : '';
$separator = isset($separator) ? $separator] : '-';
$urlEncode = isset($urlEncode) ? $urlEncode : false;
$allowedChars = isset($allowedChars) ? $allowedChars : array();
$charsToRemove = isset($charsToRemove) ? $charsToRemove : array();
....
Same implementation, but shorter.
I'm used to the habit of checking the type of my parameters when writing functions. Is there a reason for or against this? As an example, would it be good practice to keep the string verification in this code or remove it, and why?
function rmstr($string, $remove) {
if (is_string($string) && is_string($remove)) {
return str_replace($remove, '', $string);
}
return '';
}
rmstr('some text', 'text');
There are times when you may expect different parameter types and run different code for them, in which case the verification is essential, but my question is if we should explicitly check for a type and avoid an error.
Yes, it's fine. However, php is not strongly typed to begin with, so I think this is not very useful in practice.
Additionally, if one uses an object other than string, an exception is a more informative; therefore, I'd try to avoid just returning an empty string at the end, because it's not semantically explaining that calling rmstr(array, object) returns an empty string.
My opinion is that you should perform such verification if you are accepting input from the user. If those strings were not accepted from the user or are sanitized input from the user, then doing verification there is excessive.
As for me, type checking actual to data, getted from user on top level of abstraction, but after that, when You call most of your functions you already should now their type, and don't check it out in every method. It affects performance and readability.
Note: you can add info, which types is allowed to arguments for your functions by phpDoc
It seems local folks understood this question as "Should you verify parameters" where it was "Should you verify parameter types", and made nonsense answers and comments out of it.
Personally I am never checking operand types and never experienced any trouble of it.
It depends which code you produce. If it's actually production code, you should ensure that your function is working properly under any circumstances. This includes checking that parameters contain the data you expect. Otherwise throw an exception or have another form of error handling (which your example is totally missing).
If it's not for production use and you don't need to code defensively, you can ignore anything and follow the garbage-in-garbage-out principle (or the three shit principle: code shit, process shit, get shit).
In the end it is all about matching expectations: If you don't need your function to work properly, you don't need to code it properly. If you are actually relying on your code to work precisely, you even need to validate input data per each unit (function, class).
I'm wondering what you think the best practice is here-- does it buy you very much to type-check parameters in PHP? I.e have you actually seen noticeably fewer bugs on projects where you've implemented parameter type-checking vs. those that don't? I'm thinking about stuff like this:
public function __construct($screenName, $createdAt) {
if (!is_string($screenName) || !is_string($createdAt) {
return FALSE;
}
}
Normally within a PHP application that makes use of the skalar variable "types" is bound to actually string input (HTTP request). PHP made this easier so to convert string input to numbers so you can use it for calculation and such.
However checking scalar values for is_string as proposed in your example does not make much sense. Because nearly any type of variable in the scalar family is a string or at least can be used as a string. So as for your class example, the question would be, does it actually make sense to check the variable type or not?
For the code you proposed it does not make any sense because you exit the constructor with a return false;. This will end the constructor to run and return a not-properly-initialized object.
Instead you should throw an exception, e.g. an InvalidArgumentException if a constructors argument does not provide the expected / needed type of value.
Leaving this aside and taking for granted that your object constructor needs to differ between a string and an integer or bool or any other of the scalar types, then you should do the checks.
If you don't rely on the exact scalar types, you can cast to string instead.
Just ensure that the data hidden inside the object is always perfectly all-right and it's not possible that wrong data can slip into private members.
It depends. I'll generally use the type-hinting that is built into PHP for higher-level objects ((stdClass $obj, array $arr, MyClass $mine)), but when it comes to lower level values -- especially numbers and strings, it becomes a little less beneficial.
For example, if you had the string '12345', that becomes a little difficult to differentiate between that and the number 12345.
For everything else, the accidental casting of array to a string will be obvious. Class instances which are cast to strings, if they don't have a __toString, will make PHP yell. So your only real issue is classes which have a __toString method and, well, that really limits the number of times where it can come up. I really wonder if it is worth that level of overhead.
Checking function arguments is a very good practice. I suspect people often don't do that because their functions grow bigger and the code becomes uglier and less readable. Now with PHP 7 you can type-hint scalar types but there is still no solution for cases when you want your parameter to be one of two types: array or instance of \Traversable (which both can be traversed with foreach).
In this case, I recommend having a look at the args module from NSPL. The __constructor from your example will have the following look:
public function __construct($screenName, $createdAt)
{
expectsAll(string, [$screenName, $createdAt]);
}
// or require a non-empty array, string or instance of \ArrayAccess
function first($sequence)
{
expects([nonEmpty, arrayAccess, string], $sequence);
return $sequence[0];
}
More examples here.
Better documentation is more important when you're the only one interacting with the methods. Standard method definition commenting gives you well documented methods that can easily be compiled into an API that is then used in many IDEs.
When you're exposing your libraries or your inputs to other people, though, it is nice to do type checking and throw errors if your code won't work with their input. Type checking on user input protects you from errors and hacking attempts, and as a library letting other developers know that the input they provided is not what you're expecting is sometimes nice.
From what I know, checking preconditions is a good practice. If a method needs an int value then it's a good solution to do use something like this:
public function sum($input1, $input2) {
if (!is_int($input1)) throw new Exception('Input must be a integer');
However after looking to the source code of Zend/Codeigniter I don't see checks like this very often. Is there a reason for this ?
Because it is difficult / inefficient to test each and every variable before you use it. Instead they check just input variables - check visitors at the door, not once inside the house.
It is of course a good defensive programming technique to test at least more important vars before using them, especially if the input comes from many places.
This is a bit off-topic, but the solution I would recommend is to test input variables like this:
$username=get('username', 'string');
$a=get('a', 'int');
...
$_REQUEST and similar should never be used (or even be accessible) directly.
Also, when doing HTML output, you should always use this:
echo html($username); // replaces '<' with '<' - uses htmlentities
To avoid SQL injection attacks one can use MeekroDB, but it is unfortunately very limiting (MySQL only, single DB only,...). It has a good API though which promotes safety, so I would recommend checking it out.
For myself I have build a small DB library that is based on PDO and uses prepared statements. YMMV.
Specifying such strict preconditions in any case is not necessary and feels not useful in a dynamical typed language.
$sum = sum("1", "2");
Why one should forbid it? Additional if you throw an Exception, one tries to avoid it. This means, he will test and cast himself
function sum ($a, $b) {
if (!is_int($a)) throw new Exception('Input must be a integer');
if (!is_int($b)) throw new Exception('Input must be a integer');
return $a + $b;
}
if (!is_int($value1)) { $value1 = (int) $value1; }
if (!is_int($value2)) { $value2 = (int) $value2; }
$sum = sum($value1, $value2);
Every is_int() occurs multiple times just to avoid unnecessary Exceptions.
Its sufficient to validate values, when you receive them, not all over the whole application.
Speaking about ZF, i'd say that they try to minimize it in favour of interfaces and classes. You can see in many definitions across ZF something like this:
public function preDispatch(Zend_Request_Http $request)
which is fine enough. Also at critical places where ints/strings are needed there are some sanity checks. But mostly not in the form of is_string() but rather as isValidLocale() that calls some other class to check validity.
I am not really clear about declaring functions in php, so I will give this a try.
getselection();
function getselection($selection,$price)
{
global $getprice;
switch($selection)
{
case1: case 1:
echo "You chose lemondew <br />";
$price=$getprice['lemondew'].'<br>';
echo "The price:".$price;
break;
Please let me know if I am doing this wrong, I want to do this the correct way; in addition, php.net has examples but they are kind of complex for a newb, I guess when I become proficient I will start using their documentation, thank you for not flaming.
Please provide links that might also help me clear this up?
Your example seems valid enough to me.
foo('bar');
function foo($myVar)
{
echo $myVar
}
// Output: bar
See this link for more info on user-defined functions.
You got off to a reasonable start. Now all you need to do is remove the redundant case 1:, close your switch statement with a } and then close your function with another }. I assume the global array $getprice is defined in your code but not shown in the question.
it's good practice to declare functions before calling them. It'll prevent infrequent misbehavior from your code.
The sample is basically a valid function definition (meaning it runs, except for what Asaph mentions about closing braces), but doesn't follow best practices.
Naming conventions: When a name consists of two or more words, use camelCase or underscores_to_delineate_words. Which one you use isn't important, so long as you're consistent. See also Alex's question about PHP naming conventions.
Picking a good name: a "get" prefix denotes a "getter" or "accessor"; any method or function of the form "getThing" should return a thing and have no affects visible outside the function or object. The sample function might be better called "printSelection" or "printItem", since it prints the name and price of the item that was selected.
Globals: Generally speaking, globals cause problems. One alternative is to use classes or objects: make the variable a static member of a class or an instance member of an object. Another alternative is to pass the data as an additional parameter to the function, though a function with too many parameters isn't very readable.
Switches are very useful, but not always the best choice. In the sample, $selection could easily hold the name of an item rather than a number. This points to one alternative to using switches: use an index into an array (which, incidentally, is how it's done in Python). If the cases have the same code but vary in values used, arrays are the way to go. If you're using objects, then polymorphism is the way to go--but that's a topic unto itself.
The $price parameter appears to serve no purpose. If you want your function to return the price, use a return statement.
When you called the function, you neglected to pass any arguments. This will result in warnings and notices, but will run.