Should I always verify if an object is NULL? - php

I have a object built through a factory containing my parameters read from the url.
From this object, I can get the language parameter
$language =
$my_parameters->getLanguage();
$language is NULL if it isn't been set.
$language may also be invalid ( $language->isValid() returns false ).
So, to build my page, I need some parameters.
The page is also built trough a factory. Then I know which parameters I need to build it. If it miss parameters, I build them with a valid default value according to the page asked.
At this point, into the page factory, if a have an invalid parameter, I throw an exception.
My page object contains a body object that needs a language parameter. I know that my parameters are valid when I build my body object.
Into my body object, I retrieve the language
$language =
$my_parameters->getLanguage();
At this point, $language ** MUST ** be valid.
So I verify again
$language = $my_parameters->getLanguage();
if( is_null( $language ) or !$language->isValid() ) {
throw new Exception( 'Language must be valid.' );
}
If I need 4 parameters, I have 4 ifs that verify if the object is not NULL and not invalid.
I do it because the method is public where $language is used in the body object .
And the body object may be built outside the factory. Who knows...
Is it correct to verify in that case ?
What are the best-practices about that ?

Here is the case for not checking for null in a recent blog post from the Google Testing blog.
The argument is that it gets in the way of writing clear, easy unit tests, because you can't actually fake the pieces that don't matter, because your exceptions/assertions will be thrown.
The author (Miško Hevery) does qualify the commentary by saying that if it's an external API, it might still be worth checking for an error condition.

i know very little about your domain, but in the general case, i like to assert(not null) all over the place, because typically if i end up with a null object somewhere, its a bug.
it's also good practice to prefer reference types which typically can't even be null.

I come from a very old school of C programming; so my thing is that variables that are not being used or that have been free()'d should always be NULL. That's just my opinion though.
Edit: Building on that, you should always check to see if a variable is NULL before using it as well. If the variable is NULL and shouldn't be then you should log an error. Crashing should not be a feature.

You can make life simpler for yourself by splitting the getLanguage() into two methods:
function getLanguageIfValid() {
// this method return a Language object, but only if it can be created
// correctly and the isValid() method returns TRUE. If the Language object
// can't be created correctly, then it will return null instead.
}
function getLanguageMustBeValid() {
// this method will always return an instance of Language, or else
// an exception will be thrown
if($return = $this->getLanguageIfValid())
return $return;
throw new Exception("Couldn't get Language object");
}
Once you've done that, in places where it is reasonable to say that the language item might not be created properly, you use the first method:
// we may or may not be able to get our Language object here
if($language = $my_parameters->getLanguageIfValid())
do_stuff($language);
If you're certain the language object should be created, then use the 2nd method which will throw the exception for you.
// we know the Language object is created at this point
$language = $my_parameters->getLanguageMustBeValid();
do_stuff($language);
So the answer to your question is No - you don't have to verify an object is not null as long as you can get it from a function that us guaranteed not to return null.

Throw your exception from ->getLanguage().
To me, exceptions should be thrown automatically. What you are doing seems like a mixture of error-code checkup and exception throwing.

Related

How to access custom field property in Drupal User Object in Drupal 8

I am trying to access the content of custom fields in the user object.
Some have advocated the user of user_load. But according to Drupal, that deprecated.
in Drupal 8.x, will be removed before Drupal 9.0. Use
\Drupal\user\Entity\User::load().
So I've attempted to use Entity::load. It loads the object and in my IDE, I can see the values... but I can't seem to load a local variable with the value. Here is code that isn't working.
public function arguments($arg1) {
$userProfile = \Drupal\user\Entity\User::load($arg1);
$display_username = $userProfile->getAccountName();
$current_user = user_load($user_id);
$lastname = $userProfile->values["field_user_last_name"]["x-default"][0]["value"];
That string came from the path I saw in the object returned. However, as one can see in the screen shot from the IDE, the value comes back NULL.
I'm sure it is something simple that I'm not seeing. (missing the good old days of non-OOP!)
The $userProfile is an object so data should be called via methods.
The list of all methods can be found in Drupal documentation.
Long story short, all Drupal entities use the same methods to return field value.
The get('field_name') method returns the field object and getValue() returns the value of field.
In your case that would be:
$field_value = $userProfile->get('field_user_last_name')->getValue()[0]["value"];
By using so called magic methods the code will look even cleaner and you can simply get the value as:
$field_value = $userProfile->field_user_last_name->value;
Please note that magic methods can not be always used while standard methods can be.

How does Laravel optional() work?

When creating new models, I am trying to use the optional() helper to assign values when they are set. However, when the user object isn't set in this context, I receive this error: "Undefined property: stdClass::$user"
$this->events()->create([
'category_a' => optional($event)->categoryA,
'category_b' => optional($event)->categoryB,
'user' => optional($event->user)->accountId,
]);
To clarify, the $event is always set, however it can contain different values. Sometimes category_a is set, sometimes category_b is set. The optional helper seems to do the trick here. But, when the object is deeper than one level, it throws an error.
So how do I work with the optional helper correctly using deeper than one level objects?
The optional() helper normally is used to avoid errors generated by accesing propeties or methods on null objects, for example:
Fatal error: Call to a member function foo() on null
As the documentation specifies:
The optional function accepts any argument and allows you to access properties or call methods on that object.If the given object is null, properties and methods will return null instead of causing an error.
A practical example
In your code you are accesing a relation called address from your user model:
return $user->address->street;
If by any chance your $user->address is null and you try to check the street, this will return a fatal error, here is where optional() comes into play, by using the helper you can explicitly say $user->address might be null, so don't show me an error if that's the case:
return optional($user->address)->street;
By doing this you will get null instead of the fatal error.
In my opinion this makes the code more readable, a equivalent could be $user->address ? $user->address->street : null, but as you can see is by far more verbose.
In your case, as the comments said an option is to nest optional() helpers, but this is not maintanable if you have multiple levels. I'd recommend you to make a function that internally will chain the helpers so your syntax would look like n_optional($event, ['user'])->accountId.
Hope this helps you.
Also, bear in mind that in PHP 8+ you can use the null safe operator to have the same behavior with cleaner look:
// PHP 8+
$this->events()->create([
'category_a' => $event?->categoryA,
'category_b' => $event?->categoryB,
'user' => $event->user?->accountId,
]);
It is also chainable and can be used with methods:
// before PHP 8
$country = null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
}
// PHP 8+
$country = $session?->user?->getAddress()?->country;
Note by #pedro-x: Pay attention that optional() works for null|false values, while ?-> only works with null values. They are not the same! Pay attention to the details to avoid breaking your code.

Intercept and change function or method parameter value in error handler

In this comment in the PHP manual, a user suggested a class which would implement an error handler capable to implement primitive type hinting for PHP.
I understand how that class operates, however, I would like to know if it is possible to bring it to another level: instead of only checking the argument value to see if it matches the "typehint", would it be possible to replace the value with another one if it does match, and how?
I was thinking about something along the line of:
if(gettype($funcValue) == $typeHint) {
// here replace $funcValue, for example $funcValue = new Example($funcValue);
}
and then have the function call proceed with the new value?
I have searched the manual but found nothing which could allow me to "hook" in the parameters' values, but it could be there and I simply didn't find it.

set models based on condition in cakephp queries

This is probably very easy to do, but I can't seem to get my head around it right now. Let's say in a component in a cakephp application, I have a variable my_model, which contains the model of the corresponding controller that is currently using the component like:
function TestComponent extend Object
{
var $my_model; // can be either User, or Person
function test()
{
$myModelTemp = $this->my_model;
$model = $myModelTemp != 'User' ? $myModelTemp.'->User' : 'User';
$this->$model->find('all');
}
}
As you can see above in my function test() what I'm trying to do is call the correct model based on the value of my_model. So based on the condition, my query will be either:
$this->Person->User->find('all');
Or
$this->User->find('all');
When I do it like I did above, I get an error saying Fatal error: Call to a member function find() on a non-object. In order words, that error means Person->User is not an object (so, it is considered as a string).
What you're saying could be true, however, it can refer to any part of the call.
So either Person or User could be invalid, or together they causes the error. Hard to say.
Try dumping the individual objects using var_dump();
So try:
<?php
echo "<pre>";
var_dump(is_object($this->Person));
var_dump(is_object($this->User));
echo "</pre>";
?>
to determine where you're code goes wrong.
To be clear, that return value needs to be true for it to be an object.
The one that returns false is the likely culprit.
Should your question refer to the correct way to reference an object, an object is basically an array. For example:
<?php
$obj = (object) array("this", "my_function");
?>
The above example casts the array as an object. However, using multiple layers might prove to be more difficult than you'd expect.
Generally, it looks like you might be going about this all wrong. Obviously you want the models to be dynamic, but then you're hard-coding things which defeats the whole point of it being dynamic in the first place.
It also seems like you might be violating the principals of CakePHP and MVC by doing all this in a component. I'm not sure this component should really be manipulating models or assuming which models are currently in use.
However, if you want to evaluate a string as an actual object, you can wrap it in { ... } (this is valid standard PHP syntax, not Cake-specific code).
Try this:
$modelName = $this->my_model;
$model = ($modelName != 'User') ? $this->{$modelName}->User : $this->User;
$model->find('all');
Now, if this doesn't work or you get an error saying it can't find the model(s) you need to ensure the models are actually loaded and initialised in the current scope.

PHP - returning different types of values from same method

would it be considered bad practice to return different types from the same method in php. Maybe there is a best pattern for this but essentially i want my method to do something and if it fails return a string error message but if it works then return true. This doesnt seem quite right to me but the only other way i can see to make this work would be to return a string for the error message and a string with something like 'worked' or 'valid' or something if all goes ok. Again this means there is more coupling beetween methods that use this as they cant just check true of false but the have to know the word that will be representing a valid response from the method.
If you are trying to monitor whether a function worked, you are best served by making use of Exceptions. As in all programming languages that provide them, these are indicative of "exceptional" cases outside the confines of expected program flow, and do not require any type of return to indicate something went wrong. See the associated documentation linked below for the PHP specifics.
PHP Exceptions
Assuming that you are referring to a method in a class, it would be better to simply return a TRUE or FALSE from the method but use an $_error property in the class that can contain an array of error messages.
Then if the result is false, before returning the method can set the error message(s) in the $_error property and you can retrieve the message using a get_error() method.
Well, you could return an array, I suppose - the first index would contain your boolean true/false, and the second index would contain more information if necessary.
You can certainly get away with it in PHP, but it might cause problems down the road. Esp when you or someone else has to maintain the app in the future. In general I'd recommend avoiding any approach like this that creates an ambiguity about whats in the variable.
One way to achieve what you are doing is to have the function return a result code or message, and have the actual value that gets returned sent back using referenced parameters.
ex:
$msg = MyFunc( $o);
if ($msg == 'OK') //or ($msg == 0)
{
//use the returned object or value
$o->Foo();
}
else
{
//respond to error
}
Returning true or anything else may be a good solution. Sometimes. I't may break if you decide to change returned values. Personally, I like it.
You could return an array. If it's empty, there was no error. Every error would be a separate item in array.
Besides, you may try to throw exception.
PHP is a loosely typed language, so it's pretty ordinary in the culture of PHP to return dissimilar types from functions.
For example, mysql_query() returns a resource on success and a boolean false on error. You test for the error state and then call another function like mysql_error() to get the specific information about the nature of the error.
$query = mysql_query($sql);
if ($query === false) {
die(mysql_error());
}
However, when writing OO code, I would be cautious about returning different unrelated object types from a function. It requires developers to write lots of tedious type-checking code:
$result = $search->find($keyword);
if ($result === null) {
// no entry matches $id
} elseif ($result instanceof ResultClass) {
// one row found; do something with the result
print $result;
} elseif ($result instanceof ResultCollection) {
foreach ($result as $element) {
print $element;
}
} else {
// are there other types for $result?
}
What a pain to write all that code every time you call find()!
The above example would be better if the find() method always returned a ResultCollection. If no results are found, the collection would have zero entries. If you can assume the function returns a given type consistently, your code is simpler:
$result = $search->find($keyword);
foreach ($result as $element) {
print $element;
}

Categories