> ## Content Index
> Fetch the complete content index at: https://madewithlove.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# PHP lied to me
- URL: https://madewithlove.com/blog/php-lied-to-me/
- Published: 2024-04-08T07:43:41.000Z
- Updated: 2025-02-19T09:34:21.000Z
- Description: We discuss the challenges of using PHPStan at its strictest level for type checking, particularly with 'mixed' types. It explores solutions like using strval() and creating custom functions, but ultimately, the author opts to lower PHPStan's strictness due to complexity, ending with mixed feelings.
- Author: Stef Trenson
- Tags: Engineering, Code quality, Ideas, Processes, Laravel, Refactoring

When starting a client's project, we had to decide which PHPStan level we would use. We went for the highest level, which means the most strict checks. We reasoned that it would be better to start strict and lower it when needed.

[PHPStan](https://phpstan.org/) defines level 9, the highest level, as follows:

Be strict about the mixed type - the only allowed operation you can do with it is to pass it to another mixed

Enabling this rule makes sense when you use strict type hinting on function parameters. A function that returns a mixed variable might return an integer, and passing it to a function that expects a string would cause a crash during execution. So it would be better to know this upfront rather than when the code is running in production and you're looking at the [Sentry](https://sentry.io/welcome/) issue.

The first attempt to fix this would be casting the mixed value to a string:

```php
someFunction((string) $someMixedValue)
```

But alas, PHPStan now reports that a mixed value cannot be cast to a string.

The solution is to use PHP's `strval()` function. This function is documented as follows:

```php
function strval(mixed $value): string {}
```

We pass it a mixed value and get a string back. This makes PHPStan happy; it ensures type safety, so everyone should be satisfied.

But then came this [PR](https://github.com/phpstan/phpstan-src/pull/2354) on the PHPStan repository. The documentation on the `strval()` function is wrong. When you pass it as `stdClass`, it gives a fatal error. The change in PHPStan is because it only applies to the highest level. You probably want to know about these potential issues if you enable this. 

So, I had to figure out potential options to update to the latest version and fix those newly reported issues. It would be possible to add a `/** @phpstan-ignore-next-line */` above the offending line, but that kind of defeats the purpose of using PHPStan and could suppress other issues.

Another option would be to add a docblock that declares the variable:

```php
/** @var string $iAmAStringPinkySwear */
```

This makes PHPStan happy, but it does not protect against potential issues. Adding docblocks everywhere to type hint a variable also makes the code bulkier than it needs to be.  
A last option is to have some function or service that mimics the behavior of `strval` without lying.

```php
String::fromMixed(mixed $mixed): string
```

Internally, this function could use `strval` but ensure it does not get unsupported types. This would fix everything. However, a decision needs to be made on the string representation of a callable. Thinking about that decision explains why the core php function does not make a decision. It could also throw an exception, but then it would just be a useless wrapper around the `strval` function.

I ended up lowering the strictness level of PHPStan from 9 to 8\. Writing the service that perfectly casts a mixed variable to a string feels like writing a patch for a PHP issue and over-engineering the solution. Moreover, it would also need to be done on `intval` and similar functions because those have similar problems.

So what do you think? Should PHPStan lower its principles or have a separate strictness level for total mixed-type safety? Are there other solutions that I missed? I think PHP should just support casting callables to a string in the `strval` function. Let's just say I ended up with `mixed` feelings.