You know what? Compared to the bland and non-self-evident “protected”, “hereditary” is a remarkably apt name. I’m not sure the concept itself is that useful, but if you have to have it, why not.
I just never used it in practice. And I still don't.
Take a response caching middleware, for example, that uses a CacheStrategy class to control the behaviour of the cache. There's an interface, so we can depend on it in the middleware:
interface CacheStrategyInterface {
public function shouldCache(Request $request, Response $response): bool;
}
and there's a default implementation, shipping with the library, which works for 90% of use cases: class DefaultStrategy implements CacheStrategyInterface {
public function shouldCache(Request $request, Response $response): bool {
if ( ! $this->isMethodCachable($request)) {
return false;
}
return $this->isSuccessful($response);
}
// This method can be modified by user code: Maybe they implemented
// an API with a `"success": false` in the response body, despite
// the status code? There's no way to know that, let alone provide a
// configuration switch for every possible failure condition in user
// code implementing our middleware.
protected function isSuccessful(Response $response): bool {
return $response->isSuccessful() || $response->isRedirection();
}
// This method shall not be modified: Whether an HTTP request may be
// cached is defined by specification, not implementation.
private function isMethodCachable(Request $request): bool {
return $request->isMethodCacheable();
}
}
Users may extend this implementation, and override the `isSuccessful` method with their own implementation used to check whether a response handled by the app was actually successful (and thus should be added to the cache).This method isn't significant from the outside of the class - it would add needless weight to the API contract of our library. But still, there's value in allowing users building their own caching strategy to override it with their own checks. Such an implementation might look like this:
class CustomStrategy extends DefaultStrategy {
protected function isSuccessful(Response $response): bool {
return $response->body('success', false) === true;
}
}
There's no boilerplate here, no need to reimplement the whole shouldCache method, when only a single, granular, override is enough. And that is why protected can be helpful :)(This was taken from a Laravel library I maintain. If you want to check the full example, see here: https://github.com/matchory/response-cache/blob/master/src/S...)