Psalm possibly null value provided with request->get() - php

I have the following code:
$request->headers->get('Accept-Language', 'en');
I provide a default value but Psalm thinks it's potentially null since ->get() declares that return a nullable string:
// vendor/symfony/http-foundation/HeaderBag.php
/**
* Returns a header value by name.
*
* #return string|null The first header value or default value
*/
public function get(string $key, string $default = null) { /* */ }
How can I fix this so psalm knows it's not null?

Since you cannot control the annotation in the upstream library, you'll have to provide the missing information to Psalm in your own code.
A couple of ways to go about it:
Cast to string, so Psalm has no doubt what type get() is getting you:
$a = (string) $request->headers->get('Accept-Language', 'en');
Yup, the cast is redundant, but it's clear and concise. I usually do this just for economy.
You could explicitly declare that the variable that result of this get() call is a string:
/** #var string $acceptLanguage **/
$acceptLanguage = $request->headers->get('Accept-Language', 'en');
Finally, you can simply suppress the PossiblyNullArgument wherever you need it:
/** #psalm-suppress PossiblyNullArgument */
iWantAString($request->headers->get('Accept-Language', 'en'));
See all these working here.
You can also combine some of the above with your own wrapper method to deal with getting values from the request, making sure you always return string. If you do that, you should probably throw an exception if the parameter is not found.

In addition to #yivi's answer that shows you how you can override type inference or suppress the error, you can also explain the type to Psalm by providing correct docblock using conditional types either directly in the source code (if you have control over that) or in a stub file.
/**
* Returns a header value by name.
*
* #psalm-return ($default is null ? (string|null) : string)
*/
public function get(string $key, string $default = null) { /* */ }
https://psalm.dev/r/41b8471847

Related

Handle null value when using strict attribute type PDO::FETCH_CLASS

I'm trying to fetch all rows and set it into Inventory class. Here's my class and how I fetch it
class Inventory {
public int $id;
public string $name;
public string $type_of;
public float $weight;
}
$query = "SELECT * FROM inventories";
$inventories = $this->db->prepare($query);
$inventories->execute();
$inventories = $inventories->fetchAll(PDO::FETCH_CLASS, 'Inventory');
In DB, the type_of attribute is nullable. So, when I execute the code, it throws an error :
Typed property Inventory::$type_of must be string, null used
Is there any ways to ignore the null value and convert it to its type default value.
Example : type_of is string, when the value is null so it will change into an empty string. weight is float, then it will change into 0.0.
Thank you so much
There are two possible solutions, you could set strict_types (read more about Strict Typing) to off in PHP and you will no longer have the TypeError you are getting, or you could keep the strict_types setting as is and simply make the following change:
from
public string $type_of;
to
public ?string $type_of;
You can declare class properties to be nullable and/or to have default values.
For example:
class Inventory
{
public int $id;
public string $name;
public ?string $type_of = null;
public float $weight = 0;
}
You may find this blog post helpful.

Arguments and type declarations using "?" for nullable values

PHP Version 7.3.8
References:
https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration
I've been reading this sentence on the above page:
As of PHP 7.1.0, return values can be marked as nullable by prefixing the type name with a question mark (?). This signifies that the function returns either the specified type or NULL.
The following values were passed and the results are documented here:
$marketID = 'abcdef'; // Result is: Throws a type error.
$marketID = '12345'; // Result is: It will be cast as an int.
$marketID = 12345; // Result is: It will successfully execute.
$marketID = null; // Result is: It will successfully execute.
// App controller
protected function setMarketID(?int $marketID)
{
$this->marketID = $marketID;
return $this;
}
protected function getMarketID()
{
// Will return an int or null.
return $this->marketID;
}
Is it considered acceptable to code like this. IE: Use (?) in this way to accept type and null as the manual states return values can be marked... NOT incoming values but it works? (Please see Edit)
Edit for anyone in the future reading this post:
// Will return an int or null.
If you pass an int argument to the setter the getter will automatically return an int and if you pass a null argument to the setter the getter will automatically return null.
#yivi
Yes very helpful thanks. I have added strict types and it works perfectly and I have also added your advice of declaring a return value. IE:
protected function getMarketId():?int
And again works perfectly.
You haven't declared a single return type in your example.
In setMarketId() you declared a parameter type (?int). So this method will accept either an integer or null.
If you declare you are using strict_types, then the method will not even accept '12345' or 123.5, and only accept a proper int or a null value.
Declaring a return value like the one that you expect (and consistent with what getMarketId() would return), would be accomplished like this:
protected function getMarketId():?int
{
return $this-marketId;
}
Of course it is "acceptable" to declare a type is nullable. When it makes sense or not it will depend entirely on your application, but it's a very common usage.

Check for undefined PHP method before calling?

What can I use other than if(!empty( $product->a_funky_function() )) to check if the method is empty before calling it?
I've tried method_exists() and function_exists() and a whole plethora of conditions. I think the issue is that I need to have my $product variable there.
Please help.
A fairly common pattern is to have two methods on your class, along the lines of getField and hasField. The former returns the value, and the latter returns true or false depending whether or not the value is set (where "set" can mean not null, or not empty, or whatever else you might want it to mean).
An example:
class Foo
{
/** #var string */
private $field;
/**
* #return string
*/
public function getField()
{
return $this->field;
}
/**
* #return bool
*/
public function hasField()
{
return $this->getField() !== null;
}
}
This would then be used like:
if ($foo->hasField()) {
$field = $foo->getField();
...
}
Often, like in this example, the has... method often just delegates to the get... method internally, to save duplicating the logic. If the getter contains particularly heavy processing (e.g. a database lookup or API call), you might want to factor in ways to avoid performing it twice, but that's a bit out of scope.
You need absolutely to call it so it can compute the value which it will return, so I think there is no other way to know if it will return something not empty without calling it...
You have to call it.
$result = $product->getFunction();
if(!empty($result)) {
//your code here
}

symfony2 best way to test/get a session attribute

I do this to test and get session attribute in my code :
if ($session->has("myVar")) {
$myVar = session->get("myVar");
/* do something */
}
But, I read the code of session and :
/**
* Returns an attribute.
*
* #param string $name The attribute name
* #param mixed $default The default value if not found.
*
* #return mixed
*
* #api
*/
public function get($name, $default = null);
So, if the session attribute is not find, get return "null".
if ($myVar = $session->get("myVar")) {
/* do something */
}
Or better with false, if you have "myVar" but empty, you can't rely on "null" :
if ($myVar = $session->get("myVar", false)) {
/* do something */
}
according to : Null vs. False vs. 0 in PHP
I think the third is the best, one call to $session->get, instead of has and get in my actual code.
I read about alternative comparaison with ternary operator, http://fabien.potencier.org/article/48/the-php-ternary-operator-fast-or-not, I don't use it, mostly because I.m not familiar with, but, if it's not faster, I don't need it.
Can you confirm, third is the best, and if it's not, why, and how to do best ?
That depends on what you want to achieve.
First Option
if ($session->has("myVar")) {
$myVar = session->get("myVar");
/* do something */
}
Makes sense if you want to make sure, that this var is set, and if not you actually want to set it or do anything else. It presumes that having this session variable present is a necessity
Second Option
$myVar = $session->get("myVar");
This one makes sense, if you are comfortable receiving the expected result or a null value as default if not set.
Recommendation:
$myVar = $session->get("myVar");
if (null === $myVar) {
/* do something */
}
Third Option
$myVar = $session->get("myVar", false);
This one simply allows you to override the default value if this session variable is not set
Recommendation:
$myVar = $session->get("myVar", false);
if (!$myVar) {
/* do something */
}
So, in my opinion it depends what you want to do. But there is no best or worst way as you asked for, since they all differ from each other.

How to use phpDoc with overloaded methods?

Let's say I have a PHP class called Color, it's constructor accepts various params.
// hex color
$myColor = new Color('#FF008C');
// rgb channels
$myColor = new Color(253,15,82);
// array of rgb channels
$myColor = new Color(array(253,15,82));
// X11 color name
$myColor = new Color('lightGreen');
How should I use phpDoc to create API documentation for constructor and other methods like this?
How to use phpDoc with overloaded methods?
class Color {
/**
* Constructor
* what should be here?
*/
public function __construct() {
/* CODE */
}
}
Just my point of view, but you should not have multiple constructors in the first place - your constructor is going to be full of if/else-ladders, which really isn't a good idea, especially for something lightweight like a representation of a Color.
I strongly encourage you to try something like this instead:
class Color
{
protected function __construct($r, $g, $b)
{ ... }
public static function fromHex($hex) {
return new Color(...);
}
public static function fromRGB($r, $g, $b) { ... }
public static function fromArray(array $rgb) { ... }
...
}
Now, in consumer code, instead of somewhat mysterious and ambiguous constructor calls like these:
$a = new Color(0,0,0);
$b = new Color('#000000');
Instead you can have more legible and semantic consumer code, like this:
$a = Color::fromRGB(0,0,0);
$b = Color::fromHex('#000000');
This probably makes more sense to somebody reading the consumer code, it eliminates the logic required to make the ambiguous constructor work, and as a bonus (if you're using an IDE such as PhpStorm) you can have all your inspections pass. If you're running a documentation generator, this also ensures that all the options are documented individually, rather than lumped together in a verbal description.
Note that I declared the constructor protected - this is a personal preference, but if I'm going to have multiple static factory-methods, I prefer to see those consistently used in consumer code, rather than sometimes seeing Color::fromRGB(...) and other times new Color(...).
I think that is better to use #method annotation for class/interface, which declares overloading methods. This question is interesting for me too.
/**
* #method void setValue(int $value)
* #method void setValue(string $value)
* #method void setValue(string $value, int $startFrom)
*/
class Example
{
public function setValue($arg1, $arg2)
{
// ...
}
}
See http://phpdoc.org/docs/latest/references/phpdoc/tags/method.html
Because you allow variable length arguments there are two ways I would do this.
I would simply list the allowed arguments are parameters.
/**
* #param mixed $arg1 ... description
* #param mixed $arg2 ... description
* #param mixed $arg3 ... description
*/
public function __construct() {}
Or I would simply provide an explanation with some examples.
/**
* Explanation of different expected argument combinations.
*/
public function __construct() {}
Another alternative, since only one of the examples has more than one argument, would be to simply define the arguments in the method signature making the last 2 optional. Like this:
/**
* #param mixed $arg1 ...
* #param int $arg2 ...
* #param int $arg3 ...
*/
public function __construct($arg1, $arg2 = null, $arg3 = null) {}
I know of no elegant way to do this with phpDoc. The phpDoc comment/api formatting is based on a the Javadoc format. Javadoc doesn't have a feature set to support this because in java, if you want a method to have a variable number of arguments you re-declare the method prototype for each variation.
public double foo() {
}
public double foo(double my_param) {
}
So, my performance preference is to do something like
/**
* My General description
*
* Here explain what each argument combination can do
* #param mixed $arg1 can be array, string, hex as string, or int
* #param int $arg2 if arg1 is int, then this is etc, otherwise optional
* #param int $arg3 if ar1 is int, then this is etc, otherwise optional
*/
but this may not play nice with the various auto-documentation tools.
The according to Hoyle way to accomplish this can be found at the phpDoc site.

Categories