Extending helpers

Have you ever extended a helper keeping original helper name?

  • Yes
  • No

0 voters

Have you ever extended a helper choosing a new name?

  • Yes
  • No

0 voters

If you’ve answered “Yes”, please elaborate about your case.

See discussion at https://github.com/yiisoft/yii-core/issues/176

I often extend \yii\helpers\Html in my projects to add some shortcuts (like yii2-bootstrap does for icon()) or to customize some default output (like Html::mailto()). I keep the Html name for the class.

1 Like

I only once extended Html helper with new name and only because there were some project specific methods.

Would that be a big loss if we’ll mark all helpers as final and remove base classes?

I could live with final helpers, but I really don’t see what’s the motivation behind making helpers final.
Why wouldn’t we be able to extend a helper to make it even more helpful for our specific cases?

2 Likes

Interesting comment in an interesting article: https://ocramius.github.io/blog/when-to-declare-classes-final/#comment-2378121541

To be honest I’ve never understood the idea of making it with Base class and the other. But I would not make helper class final though. It might make someone’s life more difficult.

5 Likes

Because of the class’s name. I prefer Arrays over ArrayHelper. I think that classes which represent helper class should be “finite”, that is final, because they only possess static methods.

It is a deal breaker for me. I almost always extend some base helpers (Html, StringHelper, ArrayHelper) and some base classes (like forms or AR), and then never use Yii versions directly. It is easier to add some global features or switch to different implementation when you have such “abstraction”.

What is the benefit of making them final?

2 Likes

By “new name” you mean new class name (like HtmlHelper instead of just Html) or new FQN (like app\helpers\Html instead of yii\helpers\Html)?

What kind of profit from finalization classes with static methods?

Both are valid cases for “choosing a new name”.

Possible profit is that standard behavior will be fixed in stone. See https://github.com/yiisoft/yii-core/issues/176#issuecomment-476387600

I really don’t get your point. If I create my own app\helpers\Html class which extends yii\helpers\Html how this could affect extensions or project in implicit way? My custom implementation will be used only if app\helpers\Html will be used explicitly, places where yii\helpers\Html is used will not be affected.

1 Like

Because of the class’s name. I prefer Arrays over ArrayHelper. I think that classes which represent helper class should be “finite”, that is final, because they only possess static methods.

This does not really matter because of late static binding.

In general I am a fan of keeping things as extensible and flexible as possible. Yes, designers think about what they do and they have good reasons for their decisions. But they might have not thought the same as I need at that moment - and then it’s a bit annoying not to have a point to hook in to change the behavior easily.

As for the Helpers and keeping same class name: It’s no big deal to write a own helper doing the things the way I want. But: it does not help if 3rd party components use the helpers and I want to add some functionality to the helpers for them, too.

It does not.

Currently there are two approaches:
Many helpers have a BaseXxxxx class which do the actual work and an extended class which do not add functionality, but are there just to have a nice name.

If you implement your own class with the same name and in the same namespace as the “standard” Yii helper you can add/modify functionality.

The approach is not to extend yii\helpers\Html, but yii\helpers\BaseHtml and give your class the name \yii\helpers\Html and include it manually. This way your specific implementation is used everywhere in the application.

Hi,

please don’t make helpers final.
It’s useful for the orientation to keep original class names while changing only namespace.
So I often extend yii\ns\class to app\ns\class - then I know what the class does consistently with framework purpose anywhere in the code.

BTW - I also don’t see benefit to make ANY framework class final.
E.g. I often extend yii\web\Application, yii\web\Request etc - if you make it final it will be big minus from my point of view. Such a critical BC break should be severely discussed and voted.

IMHO - framework should be a flexible tool. Final classes belong to application only.

I have to second @rob006. I always extend Html, Url, StringHelper and ArrayHelper and also some core widgets like ActiveForm and ActiveField, too. I keep the original names but I always use a different namespace. It would mean a ton of extra work for me if these and other core classes would be marked as final.

  1. Much less maintenance burden. You can freely use private properties.
  2. No creative ways of extending a class. Don’t have to take care about extension points that were not designed to be extendable.
  3. final forces using composition instead of inheritance. That’s usually a good thing. Makes code less fragile.

We’ve a variety of additions and changes in Html.

Url has a method with business logic to generate links to a special class of pages. We pass an AR instance and it figures out the rest.

ConsoleHelper has some logging features that we use for daemons.

HtmlPurifier has a custom configuration used in an override of process()

DateTime isn’t really a helper but we added a variety of thing including SQL format constants and business logic that’s useful in method chaining.

And we’ve a class

class Utc extends \DateTimeZone
{
    public function __construct()
    {
        parent::__construct('UTC');
    }
}

which improves readability in this common construct

$x = new \DateTime($y, new Utc);

We even have a special linter rule to allow construction of that specific class without the () appendage.

1 Like