Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Uniwersalne tworzenie obiektów klas o nazwach ze string'a
Forum PHP.pl > Forum > Przedszkole
eerie
Sorry, jeśli odpowiedź na moje pytanie jest banalna. Jednak szukam w Google i nie mogę nic znaleźć.

Chcę przekazywać parametrem metody stringi (np. 'NewClass'), na podstawie których będę tworzyć obiekty (np. $object = new NewClassModel()). Potem chcę te obiekty zwracać (return $object). Chodzi o to, aby to było uniwersalne. Jak to prosto zrobić?
nospor
a
  1. $zm = 'NewClass';
  2. $object = new $zm;

nie dziala?
eerie
Działa. Aż się zawstydziłem. smile.gif
nospor
wybacz moje glupie pytanie ale po co ci to? Co ty chcesz tutaj zrobic bardziej uniwersalnego? Boje sie, ze cos probujesz przekombinowac
eerie
Chciałem zrobić odwołania do modelu podobnie, jak jest w Symfony. Np. coś w tym stylu:

Kod
$sr = $model->getRepository('Site');
$sr->setMethod($id, $varible);


Ale właśnie zauważyłem, że to nie jest najlepsze rozwiązanie. W Symfony jest używany menadżer:

Kod
$em = $this->getDoctrine()->getManager();
$em->getRepository('App:Site')->setMethod($id, $varible);


Chodzi mi o to, aby nie wstrzykiwać do kontrolera kilku obiektów z repozytoriami (np. dla UserRepository, SiteRepository oddzielnie), ale aby to zrobić uniwersalnie. Tworzyć jeden obiekt (np. w index.php). Połączyć się z bazą. Wstrzyknąć go do kontrolera i potem używać tego repozytorium, które jest mi akurat potrzebne. Jednak widzę, że tak tego nie zrobię. Prosiłbym o sugestie, jak to zrobić lepiej. wink.gif

Podobnie planuję postępować z kontrolerami. W index.php, na podstawie parametru z .htaccess, tworzyć uniwersalnie obiekt kontrolera, który jest mi akurat potrzebny. Przekazywać mu metodą obiekt mojego modelu, tablicę wyników z formularza i sesję.

Ok. Wersje robocze klas wyglądają na chwilę obecną tak:

Kod
<?php

declare(strict_types=1);

namespace App\Core;

use App\Core\Model;

class Controller
{
    public function getManager(): object
    {
        $model = new Model();
        $model->dbConnect();

        return $model;
    }
}


Kod
<?php

declare(strict_types=1);

namespace App\Core;

use App\Core\DataBase;

class Model extends DataBase
{
    public function getRepository(string $name): object
    {
        $class = $name . 'Repository';

        return new $class;
    }
}


Kontrolery mają rozszerzać klasę Controller. Przykładowe użycie:

Kod
$mm = $this->getManager();
$mm->getRepository('Site')->setMethod($id, $variable);
$variable = $mm->getRepository('Site')->getMethod($id);


Może tak pozostać? Prosiłbym o ocenę kodu i uwagi. smile.gif

PS Właśnie zauważyłem, że jest jeszcze jedne problem. Da się użyć jakiegoś uniwersalnego "use" dla moich klas z repozytorium? Bo teraz wywali błąd...
nospor
Ok, takie uzycie dynamicznych nazw klas ma sens.

Nie mniej jednak naduzywasz typu "object" a tym samym powodujesz ze twoje metody moga zwracac praktycznie wszystko a nie powinny. metoda model ma zwracac Model a nie dowolny object.
Tak samo getRepository() ma zwracac obiekt repository a nei dowolny obiekt. Utworz interfejsy i mow ze metody maja zwracac obietky tych interfejsow
eerie
Widzę, że źle zrozumiałem ostatnią zasadę SOLID. Zasada odwrócenia odpowiedzialności (ang. dependency inversion principle) mówi, iż wszystkie zależności powinny w jak największym stopniu zależeć od abstrakcji, a nie zależeć od konkretnego typu. Doszedłem do wniosku, iż typ object to najlepiej zapewnia. Dlatego stosowałem object praktycznie wszędzie. Rozumiem, iż mam stosować interfejsy. I tu mam pytanie: Po czym mogę określić, czy mam użyć typu object, interfejsu bądź konkretnej klasy?

Co do mojego kodu. Czy każdorazowe używanie, przy każdym wywołaniu dowolnej metody z repozytorium, metody getRepository() jest poprawne? Chodzi mi o to, iż wielokrotnie tworzony jest obiekt tego samego repozytorium...

I jeszcze: Gdzie powinienem umieszczać interfejsy? Mogę je dodawać zbiorczo do katalogu Interface?
nospor
Cytat
Po czym mogę określić, czy mam użyć typu object, interfejsu bądź konkretnej klasy?

Object wtedy, gdy naprawde bedziesz zwracal totalnie rozne obiekty w zaden sposob ze soba nie powiazane.
W przeciwnym wypadku raczej zawsze interfejsy.

Cytat
Co do mojego kodu. Czy każdorazowe używanie, przy każdym wywołaniu dowolnej metody z repozytorium, metody getRepository() jest poprawne? Chodzi mi o to, iż wielokrotnie tworzony jest obiekt tego samego repozytorium...

Dobrze by klasa z ta metoda miala wewnetrzny cache (tablice) ktore bedzie pamietac raz utworzony repository

Cytat
jeszcze: Gdzie powinienem umieszczać interfejsy? Mogę je dodawać zbiorczo do katalogu Interface?
Jak tak robie.
eerie
Słowo "Interface" jest w PHP zajęte. Chyba nie mogę w takim katalogu przechowywać wszystkich moich interfejsów. Jak więc najlepiej będzie nazwać folder z interfejsami? Gdzie je przechowywać?

I jeszcze nie wiem, jak nazywać interfejsy w PHP. Np.: RepositoryInterface czy iRepository? Jakie nazewnictwo jest poprawne?
nospor
katalog Contracts
eerie
Ok. Nikt nie odpowiedział na moje pytanie odnośnie interfejsów w oddzielnym temacie, więc zrobiłem to na czuja. PHP nie wywala błędów i niby wszystko działa ok, ale nie jestem pewny, czy jest to napisane fachowo...

Kod
<?php

declare(strict_types=1);

namespace App\Repository;

use App\Contract\{ModelInterface, RepositoryInterface};

class TestRepository implements RepositoryInterface
{
    protected ModelInterface $model;

    public function __construct(ModelInterface $model)
    {
        $this->model = $model;
    }

    // [...]
}


Kod
<?php

declare(strict_types=1);

namespace App\Core;

use App\Contract\ModelInterface;
use App\Core\Model;

class Controller
{
    protected Model $model;

    public function getModelManager(): ModelInterface
    {
        if (!isset($this->model)) {
            $this->model = new Model();
            $this->model->dbConnect();
        }

        return $this->model;
    }
}


Kod
<?php

declare(strict_types=1);

namespace App\Core;

use App\Contract\{ModelInterface, RepositoryInterface};
use App\Core\DataBase;

class Model extends DataBase implements ModelInterface
{
    protected array $repository;

    public function getRepository(string $name): RepositoryInterface
    {
        $class = 'App\\Repository\\' . $name . 'Repository';
        $this->repository[$name] questionmark.gif= new $class($this);

        return $this->repository[$name];
    }
}


Kod
<?php

declare(strict_types=1);

namespace App\Contract;

use App\Contract\ModelInterface;

interface RepositoryInterface
{
    public function __construct(ModelInterface $model);
}


Kod
<?php

declare(strict_types=1);

namespace App\Contract;

use App\Contract\RepositoryInterface;

interface ModelInterface
{
    public function getRepository(string $name): RepositoryInterface;
}
viking
Trochę mało uniwersalne jak dla mnie. Już samo ustawianie $class = 'App\\Repository\\' . $name . 'Repository'; eliminuje ładne użycie ::class. Nie bardzo rozumiem czemu controller tworzy połączenie z bd dla modelu i dlaczego jest ustawiany model a nie repo. Ale nawet jeśli co gdyby chcieć użyć 2 modele? Co jeśli chciałbyś miec 2 instancje modelu (trochę ciężko ustalić co wg ciebie znaczy model - )? Albo co jeśli model to nie zwykła baza tylko np elasticsearch?
eerie
Cytat
Trochę mało uniwersalne jak dla mnie. Już samo ustawianie $class = 'App\\Repository\\' . $name . 'Repository'; eliminuje ładne użycie ::class.

Z zapisem ::class spotkałem się przy programowaniu w Symfony, ale zbytnio jeszcze nie wiem, jak tego używać samemu. Muszę doczytać...

Cytat
Nie bardzo rozumiem czemu controller tworzy połączenie z bd dla modelu i dlaczego jest ustawiany model a nie repo.

Z tym tworzeniem obiektu db z poziomu kontrolera spotkałem się we framework'u Symfony. Zrobiłem tak, aby było niemal identyczne wywołanie metod. W Symfony z poziomu kontrolera pobierane jest Doctrine i dalej Menadżer Encji. Z menadżera pobierane są Repozytoria i dalej wywoływane ich metody. Co do nazwy klasy Model. Lepiej będzie, aby klasa zarządzająca repozytoriami nazywała się po prostu Repository?

Cytat
Ale nawet jeśli co gdyby chcieć użyć 2 modele? Co jeśli chciałbyś miec 2 instancje modelu (trochę ciężko ustalić co wg ciebie znaczy model - )?

Model odpowiada u mnie za jednokrotne połączenie z bazą danych i zarządzanie repozytoriami. Mogę mieć jeden obiekt modelu (menadżera), który tworzy i zwraca dowolną ilość repozytoriów. Tak jest w Symfony...

Cytat
Albo co jeśli model to nie zwykła baza tylko np elasticsearch?

Czyli jak? Starczy, że zmienię nazwę klasy Model (mojego menadżera repozytoriów) na np. Repository i będzie już dobrze (brak konflików)? Bo zbytnio chyba nie do końca zrozumiałem, w czym tkwi problem. Chodzi o samą nazwę klasy Model?
viking
To pytanie pomocnicze? Po co tworzysz jakieś własne hokus pokus zamiast użyć poprawnie Symfony? Skoro i tak robisz kopię S. Popracuj z jakimś większym FW, zobacz jak robi się pewne rzeczy, zdobądź doświadczenie.
eerie
Cytat
Po co tworzysz jakieś własne hokus pokus zamiast użyć poprawnie Symfony? Skoro i tak robisz kopię S.

Zamierzam docelowo (zawodowo) programować w gotowych frameworkach, ale pomyślałem, że fajnie byłoby zrobić coś podobnego samemu. Tylko mój framework miał być dużo bardziej prosty w zapisie. Takie minimum kodu i podobny efekt końcowy.

Cytat
Popracuj z jakimś większym FW, zobacz jak robi się pewne rzeczy, zdobądź doświadczenie.

Ok. Poprawię ten mój framework po swojemu i będę powoli rozwijał wraz z rosnącą wiedzą. Generalnie wszystko można zapisać na miliony sposobów i rozchodzi się tylko o przestrzeganie pewnych wytycznych oraz ogólnie przyjętych zasad. wink.gif
Pyton_000
Zamiast tracić czas na tworzenie własnego FM skupiłbym się raczej na popraacowaniu nad architekturą. Poczytaj o DDD, o CQRS, kolejki, middleware, poznaj smaczki SF żebyś wiedział jak działa. Poznaj Doctrine a zobaczysz jak działa Proxy, zobaczysz jak się zachowuje.

Na prawdę tworzenie własnego FW w tych czasach to marnowanie czasu. Chyba że robisz to sam dla siebie od tak żeby się pobawić.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.