-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add PHP 8.1 Compatibility #558
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love the idea of having a custom interface to Serializable and an OR check on type.
I don't think we get enough and it introduces confusion. I appreciate that throwing exceptions for unimplemented functions isn't ideal either but it's clear to a developer very quickly that this function won't work.
How would you feel about implementing an Abstract class that implements Serializable. The abstract class can leave the serialize function abstract so it must be implemented by anything that extends it and implements a stub unserialize as they are today?
That would mean that TraceChain, et al. would extend this new abstract class vs a new interface.
Thoughts?
I definitely see your point. Let me walk through this option. To do an abstract class we would need to throw implementation errors on both An abstract implementation would look something like this... class AbstractSerializable implements \Serializable
{
abstract public function serialize();
public function unserialize(string $serialized)
{
throw new \Exception('Not implemented.');
}
public function __serialize(string $serialized): array
{
throw new \Exception('Not implemented.');
}
public function __unserialize(array $data): void
{
throw new \Exception('Not implemented.');
}
} Usage of this class would look something like this... namespace Rollbar\Payload;
use Rollbar\SerializerInterface;
class TraceChain implements SerializerInterface
{
// Other methods
public function serialize()
{
$mapValue = function ($value) {
if ($value instanceof \Serializable) {
return $value->serialize();
}
return $value;
};
return array_map($mapValue, $this->traces);
}
} This all seems fine. However, our return type on interface Serializable {
public serialize(): ?string;
public unserialize(string $data): void;
} Fortunately, the return types on I agree that a custom interface that really just replaces a built-in interface and then running checks against class implementations of two interfaces, is definitely not ideal. Both the new interface and the abstract class solution have tradeoffs that I'm not thrilled about. I am open to either solution. What would you prefer to see? |
for the thread, @danielmorell and I chatted off-thread and decided on some next actions. We've decided to follow the direction in Daniel's original PR with some additions.
From our conversation some context from Daniel for deprecation of
Open to feedback from the community at-large about how we should approach. |
Status Update: I have made the change @cyrusradfar and I talked about, but need to make some updates to our unit tests. I will try to have that done soon. |
* @throws \Exception If Serializable::serialize() returns an invalid type an exception can be thrown. | ||
* This can be removed once support for Serializable has been removed. | ||
*/ | ||
protected function resolveCustomContent(mixed $custom): array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method was added so that we could simplify/consolidate the logic around transforming the custom
parameter into an array.
I tossed around the idea of making this method recursive. So, it could handle a nested object or multidimensional array. However, recursion could cause a lot of issues if we ran into circular references. I also don't know if we even support multidimensional data on the Rollbar server processing side. After I had thought about it a bit. I decided recursion is not a good idea here.
This is partly why I also deprecated the use of an object that does not implement the new Rollbar\SerializerInterface
interface. We probably should not just be trying to serialize someone else's object without them having a very clear understanding of what will be included. This should be done by them explicitly including it in the serialize()
method.
@cyrusradfar this is ready for you to take a look at it again. I made a few design decisions that we have not explicitly talked about that are worth noting.
I added test coverage for the new logic. We only tested |
Thank you @danielmorell for all the changes and improvements in this PR. I appreciate that we're moving to be more type specific across the SDK and managing expectations with our community that we're following the ever-changing norms and standards of the PHP eco-system. |
Description of the change
This PR primarily is designed to resolve some compatibility issues with PHP 8.1.
The major change in this PR is the removal of the PHP built in interface
Serializable
from Rollbar payload objects. I have replacedSerializable
with a new interface I created calledSerializerInterface
.Why this change?
The intent for the built in PHP
Serializable
interface has been updated with PHP 8.1. It now also should declare objects to be compatible with the built inserialize()
andunserialize()
functions. Note I am referring to the built in functions not the class methods. For instance you could do the following....With the release of PHP 8.1 classes which implement
Serializable
without also implementing__serialize()
and__unserialize()
(which were added in PHP 7.4) will generate a deprecation warning. This has been noted by #555.Our intent in implementing the
Serializable
interface has been to make objects transformable into strings that can be sent to the Rollbar service. This is why we never implemented theunserialize()
method. We only encoded the data so it could be transferred. We never needed to decode it. Because of this we don't really need to implement theSerializable
interface since doing so should represent a guarantee we probably have no intention of making.My solution was to create a new interface
SerializerInterface
that has a single methodserialize()
. This should not introduce any breaking changes since the__serialize()
method notserialize()
is called by the built inserialize()
function.The second change in this PR is to add some additional type declarations to the
Response
class. This resolves some type warnings that were raised during linting.Type of change
Related issues
Checklists
Development
Code review