PHP

Metody statyczne

Nie zalecane jest korzystanie z metod statycznych w kodzie, używanie takich metod musi mieć swój powód !

Wyjątki:

  • helper
<?php

class HtmlHelper
{
    public static function a($url, $text): string
    {
        return sprintf('<a href="%s">%s</a>', $url, $text);
    }
}

HtmlHelper::a('https://done.pl', 'Done'); 

Jeżeli tworzymy helper który zawiera bardzo proste funkcjonalności (nie korzysta z zewnętrznych baz, api itd),
to funkcjonalność powiązana jest z klasą "helper" bardziej jako spójne miejsce w którym wrzucamy funkcjonalność wokół np HTML.
Taki helper powinien być wywoływany wyłącznie na widoku/ w kontrolerze ale nigdy w naszej logice
(proste przetwarzanie danych powinno być na wejściu lub na wyjściu)
np mechanizm do tłumaczeń, tworzenia html, operacji na stringach, formatowanie ciągu znaków

  • Wzorzec factory method
<?php

class Prostokat
{
    private $a;
    private $b;

    public static function factoryKwadrat($a): self
    {
        return new Prostokat($a, $a);
    }

    public function __construct($a, $b)
    {
        $this->a = $a;
        $this->b = $a;
    }

    public function obwod(): float
    {
        //...
    }
} 

W innych językach możemy mieć więcej niż jeden konstruktor w php ten patent można uzyskać stosując "factory method"

Dodatkowo nazwa fabryki może nam coś mówić o tym jaki obiekt utworzymy np Prostokat::factoryKwadrat(5); utworzy nam prostokąt o właściwościach kwadratu, inne przykłady to np

"Dopuszczalne" jest również skorzystanie z przykładu gdzie np obiekt tworzony bedzie korzystał z danych które może nie mogą być prosto wstrzyknięte np

<?php

class Prostokat
{
    private $a;
    private $b;

    public static function factoryYiiParams(): self
    {
        return new Prostokat(
            Yii::$app->params['globalA'],
            Yii::$app->params['globalB']
        );
    }

    public static function factorySession(): self
    {
        return new Prostokat(
            Yii::$app->session->get('globalA'),
            Yii::$app->session->get('globalB')
        );
    }

    public function __construct($a, $b)
    {
        $this->a = $a;
        $this->b = $a;
    }
//...
} 

Mamy tu możliwość skorzystania np z mechanizmów yii ale to, że utworzymy obiekt z danych z params lub sesji nie wpływa na to ze klasę
można utworzyć bez tych mechanizmów, np gdy chcemy przetestować klasę a nie chcemy stawiać yii do tego

Yii i statyczny dostęp do aplikacji

w Yii często korzysta się z aplikacji za pomocą np Yii::$app->session->get('globalA') o ile nie jest to jakąś tragiczną praktyka w kontrolerach to jest sposób aby zrobić to lepiej Trzeba skorzystac z mechanizmu DI (Dependency Injection) i tak w bootstrap aplikacji trzeba ustawić mapowanie klas

bootstrap:

<?php
Yii::$container->set(\yii\web\Application::class, function () {
    return Yii::$app;
});

kontroller:

<?php

use yii\web\Application;

class PrzykladController extends Controller
{
    /**
     * @var Application
     */
    private $app;

    public function __construct(string $id, Module $module, Application $app, array $config = [])
    {
        parent::__construct($id, $module, $config);
        $this->app = $app;
    }
//...
}

W całym kontrolerze możemy używać $this->app co jest równoznaczne z korzystaniem Yii::$app, ale tym razem nie robimy tego za pomocą statica. Przydatność tego podejścia bardziej docenić mogą osoby które próbują to jakoś przetestować ale nie chcą stawiać aplikacji.

Edit on GitLab