Description
TLDR: Should JWT::decode
return array
? Conclusion: We can add this as an opt-in parameter.
Overview
In v6.1
of this library, we will be adding typed support for all parameters and return types (see #367 and #385). The current implementation of JWT::decode
can return string
, object
, or array
, depending on the value of the provided JSON string (see #370).
The Problem
Using stdClass
to represent the JWT works well and has no true issues as far as I know. However, the PHP community (as far as I can tell) seems to prefer using arrays when dealing with JSON objects. I believe this is because stdClass
is a less commonly used class, and therefore causes some confusion / inconvenience for users when working with this class. Additionally, users occasionally need to convert from stdClass
to array
when dealing with other libraries or functions.
Conversely, using array
would require everyone who uses this library to update their code to access properties with array access instead of class property access, and this is its own problem.
The Solution
The payload for JWTs will always be a JSON object. Therefore, we can throw an exception whenever the payload is a string
or an array
. This will simplify things greatly. I've already updated the tests in #385 to reflect this. So the question is more what do we want the return type to be. For this I see a few potential options:
1. The return type is always stdClass
.
This is how we have it now, but we would add typing to make this crystal clear. The advantages here is we get type safety and implement PHP best practices. The disadvantage is, as mentioned above, many users do not like dealing with stdClass
, and it occasionally causes compatibility issues when dealing with other libraries and functions
$payload = JWT::decode($jwt, $key);
echo $payload->aud;
2. The return type is always array
.
This would be a fairly major breaking change. As mentioned above, this would require almost all the users of this library to update their existing code.
$payload = JWT::decode($jwt, $key);
echo $payload['aud'];
3. Expose a way for the user to choose
Add a way to change the return type of JWT::decode
from stdClass
to an array
.
This has been suggested a few times by the community. I can think of two ways to do this:
// Option 1: with an argument
$payload = JWT::decode($jwt, $key, ['decodeAsArray' => true]);
echo $payload['aud'];
// Option 2: with a static property
JWT::$decodeAsArray = true;
$payload = JWT::decode($jwt, $key);
echo $payload['aud'];
I don't like Option 1 (with an argument) because it exposes more options on the API of the JSON::decode
function, and doesn't strike me as all that useful (it's not critical functionality).
Option 2 (with a static property) won't work. What if a dependency uses the result of JWT::decode
as a stdClass
?
4. Add helper function
We could expose a method JWT::stdClassToArray
which can convert the returned standard class to a PHP array.
$payload = JWT::decode($jwt, $key);
$payloadArr = JWT::stdClassToArray($payload);
echo $payloadArr['aud'];
This path seems fine, and could can be done reliably. But is it really necessary?
Conclusion
As a new user, I'd prefer Option 2, as working with PHP arrays is way more intuitive to me. However, as an existing user, I think maintaining the status quo (e.g. Option 1) is my preference. I assume the friction of forcing everyone to upgrade their code simply is not worth the effort. But those upgrading to the major version may be willing to update their implementation as well. If the community really wants to use arrays, we can make the switch. If most people like stdClass
, but sometimes need arrays, I think Option 3 or Option 4 may be a nice compromise.
As this is marked "RFC" (Request For Comment), I would love to get feedback on this decision before tagging v6.0
.
Which of these is your preference? Are there any options I left out?