Using callbacks to prevent code duplication

Sometimes it can be useful to use a callback function or other callable to prevent a bunch of code duplication.

Let’s say you have an event subscriber that encrypts and decrypts data in the life cycle of an entity. When the entity is stored, some data…


This content originally appeared on DEV Community and was authored by Doeke Norg

Sometimes it can be useful to use a callback function or other callable to prevent a bunch of code duplication.

Let's say you have an event subscriber that encrypts and decrypts data in the life cycle of an entity. When the entity is stored, some data will be encrypted; and when the entity is loaded, the data will be decrypted.

Here is a maybe somewhat contrived but minimal example of this:

final class EncryptionSubscriber
{
    public function __construct(private CryptographerInterface $cryptographer) { }

    private function getEncryptedProperties(Entity $entity): array {
        // some code to detect the encrypted properties of the entity.
        return ['encrypted'];
    }

    public function onSave(Event $event): void {
        $entity = $event->getEntity();

        foreach ($this->getEncryptedProperties($entity) as $property) {
            $value = $entity->getValue($property);
            $entity->setValue($property, $this->cryptographer->encrypt($value));
        }
    }

    public function onLoad(Event $event): void {
        $entity = $event->getEntity();

        foreach ($this->getEncryptedProperties($entity) as $property) {
            $value = $entity->getValue($property);
            $entity->setValue($property, $this->cryptographer->decrypt($value));
        }
    }
}

While this isn't that bad, the onSave and onLoad are practically the same method; only the content of setValue() is different. And to be honest, with two tiny functions like these; I might not bother. But it often happens that three or even more methods are the same. Or the functions are way more elaborate; while they still only differ by a tiny thing.

Extracting a callback helper

A solution to this duplication can be to extract one helper method that contains all the logic once. But at the point where the logic is different we call a callable which is injected. The original onSave and onLoad will then defer to that helper method, and provide the callable to handle the specific difference.

final class EncryptionSubscriber
{
    // ...

    public function onSave(Event $event): void
    {
        $this->processEvent($event, fn($value) => $this->cryptographer->encrypt($value));
    }

    public function onLoad(Event $event): void
    {
        $this->processEvent($event, fn($value) => $this->cryptographer->decrypt($value));
    }

    private function processEvent(Event $event, callable $callback): void
    {
        $entity = $event->getEntity();
        foreach ($this->getEncryptedProperties($entity) as $property) {
            $value = $entity->getValue($property);
            $entity->setValue($property, $callback($value)); // [tl! highlight]
        }
    }
}

As you can see, we added a processEvent() method that also receives a callable $callback. This callback is executed with the current value instead of the previous encrypt or decrypt calls. This makes the entire method a very generic implementation. Only the specific difference is handled by the callback.

If the callback needs more context to do its job, that can be added as additional parameters on the $callback() call.

While the onSave and onLoad still have some necessary duplication; the amount is way less and the difference is easier to spot. And with the help of some shorthand fn it's very readable.

Thoughts and comments?

Like I said, there is a time and place for things like this. If the duplication is minimal; you might not need to bother with it. But I think it's a nice tool to know. Do you have other nice examples where this would be useful? Please share it with the rest of us. And if you have any other comments, drop them below.


This content originally appeared on DEV Community and was authored by Doeke Norg


Print Share Comment Cite Upload Translate Updates
APA

Doeke Norg | Sciencx (2022-04-11T11:57:25+00:00) Using callbacks to prevent code duplication. Retrieved from https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/

MLA
" » Using callbacks to prevent code duplication." Doeke Norg | Sciencx - Monday April 11, 2022, https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/
HARVARD
Doeke Norg | Sciencx Monday April 11, 2022 » Using callbacks to prevent code duplication., viewed ,<https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/>
VANCOUVER
Doeke Norg | Sciencx - » Using callbacks to prevent code duplication. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/
CHICAGO
" » Using callbacks to prevent code duplication." Doeke Norg | Sciencx - Accessed . https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/
IEEE
" » Using callbacks to prevent code duplication." Doeke Norg | Sciencx [Online]. Available: https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/. [Accessed: ]
rf:citation
» Using callbacks to prevent code duplication | Doeke Norg | Sciencx | https://www.scien.cx/2022/04/11/using-callbacks-to-prevent-code-duplication/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.