Implementing isset() in a setter method - php

Is there any way to implement isset() in a setter method? That is, have the setter method check if the variable exists? From what I can tell no, but hopefully someone can confirm that for me. In a nutshell, I'm looking to avoid having to do
if (isset($arr[0])) $foo->setId($arr[0])
and simply just do
$foo->setId($arr[0])
and somehow implement the isset() logic in the setter method. Thanks!

No, you not can subscript a missing array element and expect it to work. The subscript will be evaluated before being sent to the method. This means the subscript will fail before the method even receives the argument.
Example
$arr = array(0 => 'a', 1 => 'b', 2 => 'c');
If I do $foo->setId($arr[0]) then $foo->setId() will receive a as a string, and it will never know it was subscripted from an array (not does it want to know).
So a $foo->setId($arr[3]) would give an error...
Undefined offset

No.
You're only passing the value of $arr[0] to the setter method, not the $arr[0] variable. $foo::setId has no idea of the existence of $arr or $arr[0], all it gets to see is its value.
And that's a good thing for encapsulation! Imagine if every function would have to check if its parameters actually existed:
function setId($id) {
// $id is defined, it's required (has no default value),
// and yet I can't be sure it actually exists here...?
}
You'll have to check if the variable exists before passing its value to a function.

First, read #alex's answer. (Edit: Read #deceze's answer, too)
In order to mimic what you want you can pass the array and the index separately:
$foo->setId($arr, 0);
And change the setId() method's signature (or add a safeSetId()):
function safeSetId($array, $index) {
if (isset($array[$index])) {
$this->setId($array[$index]);
}
}
This is not very pretty, though :)

Isset is not a function: it's a language construct. Language constructs are allowed to do magic; user-defined functions cant.
There is no way to reimplement the isset logic without isset itself (without modifications to PHP's source code, at least). If you try to implement it inside a function, the argument you receive will be null if the variable doesn't exist and a E_NOTICE error will be raised before your function is even called.

While you can't achieve what you're looking to do for reasons already given, you could still make the code more terse for very little overhead.
If the setId() function can handle null or if it is simply setting a member variable (which will by default be initialized to null), you could write a simple utility function like this:
function getValue($array, $key, $default = null) {
return isset($array[$key]) ? $array[$key] : $default;
}
and then call your setter like so:
$foo->setId(getValue($arr,0));
Again, there are drawbacks due to increased overhead and potential errors if your setter method expects a non-null value but this could decrease the amount of code slightly.

Related

If the variable is null or not assigned, putting value in function does not work

I have this function that sometimes does not assign the variable $infolasterroredu
In these cases I want to tell the function to assign the value "Hello" if the variable is not assigned or is null.
I tried this way but it keeps returning the value "null" when the variable is not assigned.
How would I put a default value?
I've tried all the options and nothing seems to work.
private static function stockstatus(Product $product, $infolasterroredu = 'Hello')
{
//my function code
}
The result of this code is null when debugging, what am I doing wrong?
I call the function like this
self::stockstatus($product, $infolasterroredu);
I know this can be solved this way
self::stockstatus($product, $infolasterroredu ?: "Hello");
But this would take editing all the function calls which are several so I need to do it by direct function.
Note: When I say direct function, it means directly putting the value in the private static function and not editing the calls to the function line by line, which are too many.
By not having a type at all on the second argument, you're saying anything can be passed, but if nothing is passed (not even null), it's Hello. First, I would restrict the type if possible:
function stockstatus(Product $product, string $infolasterroredu = 'Hello') {}
This doesn't solve if '' (empty string) is passed in. You could "solve" this problem with a call-side default that passes in Hello if not present:
stockstatus($product, $infolasterroredu ?: 'Hello')
The problem I see with this is that it gives an internal concern for the function to some other caller, which makes the call more brittle in case the function itself changes.
Instead, I would set it up to allow a null switch but require a string, and default internally:
function stockstatus(Product $product, ?string $infolasterroredu = null) {
$infolasterroredu = $infolasterroredu ?: 'Hello';
...
}
I'm using ?: to catch any empty or nulled value and default it to Hello. You can put 'Hello' in the default in the argument expression (this may help with type assist). However, I prefer to have someone read the function if they don't know how to call it, and I'm not duplicating the actual default value twice (in the argument default and in the internal check).
One downside, if you will, is that this accepts any truthy string, even, say or .. The best practice way of handling this is to use a value object with validation on the setter (or even a default non-thrown exception) as the second argument.
Most probably, you pass two variable names as parameters when you call. You shouldn't put 2nd argument at all.
stockstatus($productInput)
You can check if the second argument is null or not before calling the function. If you call with second parameter stockstatus($productInput, $somethingNull), it would overwrite the default value even if it's null.
There are actually some ways you could do this.
First of all, just check before calling and create your default value before:
if (!$infolasterroredu) {
$infolasterroredu = 'Hello'
}
self::stockstatus($product, $infolasterroredu);
But whenever you call the function in different places this might not be what you want.
Second way is to check for the value inside the function. So kinda the same functionality as before only you move this inside the function 'stockstatus'.
The third way is the way you want to do it. By giving a default value in the parameter. As other already pointed out, you need to call the function with only one parameter, only then PHP will fill in the default value for the missing parameters.
I would suggest the second way though.

PHP: How to pass parameter which may be undefined

I pass parameters to a function in PHP. I dont know if the parameter is defined or not.
Right now I check if the parameter is defined and cast to null if not before calling the function.
Is there a more elegant way to do it by casting or something similar? I want the function default value to be used if the parameter is not defined.
Example:
//Params['x'] may or may not be defined
// I want to use this:
a(params['x']);
//Currently I use this (which I want to avoid) :
a( isset (params['x'])?params['x']:null);
function a (data=null){
// Here I want data to be null if params['x'] is not defined.
}
It is possible if you declare this argument as reference:
function fun(&$param = null) {
}
Keep in mind, that it will also create this entry if it was not present in passed array, so if you have
$x = array('a' => 1);
And you will call fun($x['b']);, your $x will look like
$x = array('a' => 1, 'b' => null);
For everything which you're not sure exists, there has to be one point where you test that and/or ensure that it exists. You can do that with isset/empty or with an operation that ensures the value exists, like:
$params += array('x' => null);
You should not design your function to work around parameters the caller may not have. If the function requires the parameter then let it require the parameter, period. The sooner you get out of the may-or-may-not-be-there mode in your code the sooner you can require and return defined values, which cuts down on the amount of code you need to write and debug. By that I mean that the only uncertainty should be user input; punch that uncertain user input into a defined form as early as possible, after that your application internally should be strict about what it requires and what it returns and not be uncertain at every single point.
What you have already done does all you need to do.
With this function prototype you are saying, accept whatever parameter may be passed by the caller, or use NULL if nothing is passed.
function a ($data=null){
if ( $data == null ) {
// no parameter passed by caller
}
}
Just forget about all the fussing with the parameters on the call of the function. Its all done for you.

Should PHP variables be initialized prior to use as an OUT function parameter?

What is the correct way to write code that calls a function that accepts a variable pointer and changes the value?
The following works, but my IDE complains that $v is an undefined variable, which it is until the function it calls sets a value:
function foo(&$bar) {
$bar = 12345;
}
foo($v);
Should I initialize $v first to satisfy my IDE? Or is there a better way to do this?
$v = NULL;
foo($v);
When passing a variable by reference to a function, you need to have a reference to the variable from the calling code. To have a reference, the variable needs to exist. To exist, the variable needs to be initialized.
I recommend setting it to a reasonable default value. If the reasonable default is null, then use null. In some cases it may be more reasonable to use '' or 0 depending on what type of value you want the variable to hold.

Combining isset and is_null fails when checking undefined object property

I'm trying to combine isset and is_null in one function for ease of use
My approach:
class sys {
public static function is_null(&$variable) {
// if it's not set
if (!isset($variable)) {
return true;
}
// if array
if (is_array($variable)) {
return (boolean) (count($variable) < 1);
}
// if string
return (boolean) (strlen($variable) < 1);
}
}
The problem I'm having when i use it within an object is following exception:
ErrorException [ Notice ]: Indirect modification of overloaded property xxx has no effect.
For ease of use? The equivalent is return !isset($var) || empty($var);. is that so hard?
The thing that you need to realize when building a function like this, is that isset() is not a function. It's a language construct. So you can't pass a variable to a function, and then call isset on that variable (well, without generating a notice at least).
Secondly, there's no need to cast to boolean in :return (boolean) (strlen($variable) < 1);. It's exactly the same as return strlen($variable) < 1;.
Third, there's no reason to count() or use strlen(), since that's exactly what empty() was designed to check for.
Fourth, there's no reason at all to pass the argument by reference. It won't change anything, and it's needlessly creating references where there's no reason to. Just take the argument as normal (it won't use any more memory thanks to copy-on-write).
All in all, I would suggest not making this sort of "helper" function. Just use !isset($var) || empty($var) if you want to check if it's empty. It's clearer, makes more semantic sense, and frankly isn't duplicating effort. And if you don't care about the notice, you can just replace the entire call with if (empty($variable))...
But if you do use this kind of function, I'd suggest changing the name. It will return true even if the variable is not null, so calling the function is_null is down right misleading. Perhaps is_empty would be better...
just use empty()

Php function argument error suppression, empty() isset() emulation

I'm pretty sure the answer to this question is no, but in case there's some PHP guru
is it possible to write a function in a way where invalid arguments or non existent variables can be passed in and php will not error without the use of '#'
Much like empty and isset do. You can pass in a variable you just made up and it won't error.
ex:
empty($someBogusVar); // no error
myHappyFunction($someBogusVar); // Php warning / notice
You don't get any error when a variable is passed by reference (PHP will create a new variable silently):
function myHappyFunction(&$var)
{
}
But I recommend against abusing this for hiding programming errors.
Summing up, the proper answer is no, you shouldn't (see caveat below).
There are workarounds already mentioned by many people in this thread, like using reference variables or isset() or empty() in conditions and suppressing notices in PHP configuration. That in addition to the obvious workaround, using #, which you don't want.
Summarizing an interesting comment discussion with Gerry: Passing the variable by reference is indeed valid if you check for the value of the variable inside the function and handle undefined or null cases properly. Just don't use reference passing as a way of shutting PHP up (this is where my original shouldn't points to).
You can do this using func_get_args like so:
error_reporting(E_ALL);
ini_set('display_errors', 1);
function defaultValue() {
$args = func_get_args();
foreach($args as $arg) {
if (!is_array($arg)) {
$arg = array($arg);
}
foreach($arg as $a) {
if(!empty($a)) {
return $a;
}
}
}
return false;
}
$var = 'bob';
echo defaultValue(compact('var'), 'alpha') . "\n"; //returns 'bob'
echo defaultValue(compact('var2'), 'alpha') . "\n"; //returns 'alpha'
echo defaultValue('alpha') . "\n"; //return
echo defaultValue() . "\n";
This func goes one step further and would give you the first non empty value of any number of args (you could always force it to only take up to two args but this look more useful to me like this).
EDIT: original version didn't use compact to try and make an array of args and STILL gave an error. Error reporting bumped up a notch and this new version with compact is a little less tidy, but still does the same thing and allows you to provide a default value for non existent vars.
There are valid cases where checking becomes cumbersome and unnessesary.
Therfore i've written this little magic function:
/**
* Shortcut for getting a value from a possibly unset variable.
* Normal:
* if (isset($_GET['foo']) && $_GET['foo'] == 'bar') {
* Short:
* if (value($_GET['foo']) == 'bar') {
*
* #param mixed $variable
* #return mixed Returns null if not set
*/
function value(&$variable) {
if (isset($variable)) {
return $variable;
}
}
It doesn't require any changes to myHappyFunction().
You'll have to change
myHappyFunction($someBogusVar);
to
myHappyFunction(value($someBogusVar));
Stating your intent explicitly. which makes it good practice in my book.
No, because this isn't really anything to do with the function; the error is coming from attempting to de-reference a non-existent array key. You can change the warning level of your PHP setup to surpress these errors, but you're better off just not doing this.
Having said that, you could do something like
function safeLookup($array, $key)
{
if (isset($array, $key))
return $array[$key];
return 0;
}
And use it in place of array key lookup
defaultValue(safeLookup($foo, "bar"), "baz);
Now I need to take a shower :)
is it possible to write a function in a way where invalid arguments or non existent variables can be passed in and php will not error without the use of '#'
Yes you can!
porneL is correct [edit:I don't have enough points to link to his answer or vote it up, but it's on this page]
He is also correct when he cautions "But I recommend against abusing this for hiding programming errors." however error suppression via the Error Control Operator (#) should also be avoided for this same reason.
I'm new to Stack Overflow, but I hope it's not common for an incorrect answer to be ranked the highest on a page while the correct answer receives no votes. :(
#Brian: I use a trinary operation to do the check for me:
return $value ? $value : $default;
this returns either $value OR $default. Depending upon the value of $value. If it is 0, false, empty or anything similar the value in $default will be returned.
I'm more going for the challenge to emulate functions like empty() and isset()
#Sean That was already answered by Brian
return isset($input) ? $input : $default;
Sean, you could do:
$result = ($func_result = doLargeIntenseFunction()) ? $func_result : 'no result';
EDIT:
I'm sure there could be a great
discussion on ternary operators vrs
function calls. But the point of this
question was to see if we can create a
function that won't throw an error if
a non existent value is passed in
without using the '#'
And I told you, check it with isset(). A ternary conditional's first part doesn't check null or not null, it checks true or false. If you try to check true or false on a null value in PHP, you get these warnings. isset() checks whether a variable or expression returns a null value or not, and it returns a boolean, which can be evaluated by the first part of your ternary without any errors.
I'm sure there could be a great discussion on ternary operators vrs function calls. But the point of this question was to see if we can create a function that won't throw an error if a non existent value is passed in without using the '#'
While the answer to the original question is "no", there is an options no one has mentioned.
When you use the # sign, all PHP is doing is overriding the error_reporting level and temporarily setting it to zero. You can use "ini_restore('error_reporting');" to set it back to whatever it was before the # was used.
This was useful to me in the situation where I wanted to write a convenience function to check and see if a variable was set, and had some other properties as well, otherwise, return a default value. But, sending an unset variable through caused a PHP notice, so I used the # to suppress that, but then set error_reporting back to the original value inside the function.
Something like:
$var = #foo($bar);
function foo($test_var)
{
ini_restore('error_reporting');
if(is_set($test_var) && strlen($test_var))
{
return $test_var;
}
else
{
return -1;
}
}
So, in the case above, if $bar is not set, I won't get an error when I call foo() with a non-existent variable. However, I will get an error from within the function where I mistakenly typed is_set instead of isset.
This could be a useful option covering what the original question was asking in spirit, if not in actual fact.
If you simply add a default value to the parameter, you can skip it when calling the function. For example:
function empty($paramName = ""){
if(isset($paramName){
//Code here
}
else if(empty($paramName)){
//Code here
}
}
With a single line, you can acomplish it: myHappyFunction($someBogusVar="");
I hope this is what you are looking for. If you read the php documentation, under default argument values, you can see that assigning a default value to an function's argument helps you prevent an error message when using functions.
In this example you can see the difference of using a default argument and it's advantages:
PHP code:
<?php
function test1($argument)
{
echo $argument;
echo "\n";
}
function test2($argument="")
{
echo $argument;
echo "\n";
}
test1();
test1("Hello");
test1($argument);
$argument = "Hello world";
test1($argument);
test2();
test2("Hello");
test2($argument);
$argument = "Hello world";
test2($argument);
?>
Output for test1() lines:
Warning: Missing argument 1 for test1() .
Hello.
.
Hello world.
Output for test2() lines:
.
Hello.
Hello world.
This can also be used in combination to isset() and other functions to accomplish what you want.
And going further up the abstraction tree, what are you using this for?
You could either initialize those values in each class as appropriate or create a specific class containing all the default values and attributes, like:
class Configuration {
private var $configValues = array( 'cool' => 'Defaultcoolval' ,
'uncool' => 'Defuncoolval' );
public setCool($val) {
$this->configValues['cool'] = $val;
}
public getCool() {
return $this->configValues['cool'];
}
}
The idea being that, when using defaultValue function everywhere up and down in your code, it will become a maintenance nightmare whenever you have to change a value, looking for all the places where you've put a defaultValue call. And it'll also probably lead you to repeat yourself, violating DRY.
Whereas this is a single place to store all those default values. You might be tempted to avoid creating those setters and getters, but they also help in maintenance, in case it becomse pertinent to do some modification of outputs or validation of inputs.

Categories