Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Wywoływanie klasy w klasie
Forum PHP.pl > Forum > Przedszkole
sannin
Witam,

dopiero zaczynam swoją zabawę z obiektowym php. Teraz mam pytanie do bardziej zaawansowanych koderów czy moje rozwiązanie jest dobre. Więc tak mam folder gdzie tworzę pliki z klasami dajmy 'Mysql.class.php'. W pliku library.php ładuje wszystkie klasy

  1. <?php
  2. require('Mysql.class.php');
  3.     require('Main.class.php');
  4. ?>


w pliku system.php ładuje library.php i config.php Natomiast w pliku index.php mam

  1. <?php
  2. require('config/system.php');
  3.    
  4.     $mysql = new MySql;
  5.     $mysql->Connect($CONFIG['dbHost'], $CONFIG['dbUser'], $CONFIG['dbPassword'], $CONFIG['dbName']);
  6.    
  7. ...
  8.  
  9.     $index = new Main();
  10.     $index->prace());
  11. ?>


Teraz żeby uzyskać dostęp do mysql w klasie Main, metodzie prace mam coś takiego

  1. <?php
  2. function prace()  {    
  3.             global $mysql;
  4.            
  5.             $job = $mysql->selectToArray("tabela", "id, name", "id > 3", "");
  6.             foreach($job['name'] as $value) {
  7.                 echo $value.'
  8.     ';
  9.             }
  10.         }
  11. ?>


Czy ogólnie jest to poprawne podejście? Czy raczej wystrzegać się global? Jak to inaczej rozwiązać? Proszę mi nie proponować Zend'a itd. bo najpier chciałbym liznąć troszkę obiektówki smile.gif

Pozdrawiam i z góry dziękuje za pomoc.
erix
Cytat
Czy ogólnie jest to poprawne podejście? Czy raczej wystrzegać się global?

Się wystrzegać. Do tego zadania doskonale sprawdzi się singleton.
l0ud
Cytat
Się wystrzegać. Do tego zadania doskonale sprawdzi się singleton.

...który tylko 'ładniej' wygląda. tongue.gif

Utwórz klasę łączącą wszystkie (zawierającą w sobie tablicę wszystkich obiektów) i przekazuj jej instancję do wszystkich nowo utworzonych obiektów. Musi zawierać metody, dzięki którym pozwoli na dostęp do obiektów z zewnątrz, oraz najlepiej od razu je wczytywać.

Jakiś uproszczony przykład:

index.php
  1. <?php
  2. include ('includes/core.php');
  3.  
  4. $core = new core;
  5.  
  6. $core->initComponents(); //tutaj można dodać obsługę ew. wyjątków
  7. ?>


core.php

core.php
  1. <?php
  2. class core {
  3.   private $obj = array();
  4.  
  5.   public function __get($objName) {
  6.      if (isset($this->obj[$objName])) return $this->obj[$objName];
  7.   }
  8.  
  9.   public function load($className) {
  10.      include('includes/'.$className.'.php');
  11.      $this->obj[$className] = new $obj($this);
  12.   }
  13.  
  14.  public function initComponents() {
  15.     $this->load('mysql');
  16.      $this->load('config'); //itd
  17.  }
  18.  
  19. }
  20. ?>


przykładowe config.php
  1. <?php
  2. class config {
  3.   private $db;
  4.   //inne obiekty, których tutaj potrzebujemy
  5.   public function __construct(core $core) {
  6.      //wczytywanie tych obiektów do klasy
  7.      $this->db = $core->db;
  8.      //itd.
  9.   }
  10.   public function action() { //i jakaś tam akcja tej klasy
  11.      $this->db->query('zapytanie');
  12.   }
  13. }
  14. ?>


Później jeszcze możesz dodać metodę startAction() do core, które wczyta właściwy plik, który będzie coś robił winksmiley.jpg Plik zostanie wczytany wewnątrz klasy core, a więc do obiektów będziesz się odnosił tam przez $this.
erix
Uzasadnij, w jaki sposób Twoje rozwiązanie jest lepsze od singletona?
sannin
Już mniej lub więcej rozumiem o co chodzi ;p Teraz mam pytanie czy stosować new czy coś takiego
Kod
public function singleton()
    {
       static $instance;
       if(!isset($instance)) {
          $instance = new test5;
       }
       return $instance;
    }
i później
Kod
$single1 = test5::singleton();
Mize
Takie, że przykładowo w Widoku nie masz dostępu do wszystkich komponentów.
erix
Jakoś nigdy nie miałem tego typu problemów z singletonem.
l0ud
Cytat
Uzasadnij, w jaki sposób Twoje rozwiązanie jest lepsze od singletona?


Tak jak chociażby Mize powiedział, nie mogę np. w widoku wykonywać zapytań do bazy danych tongue.gif Oczywiście o ile odpowiednio go obsłużę. No i wszystko mam w jednym miejscu, co daje pewien porządek.
Równie dobrze mógłbym spytać Ciebie, w czym, poza niemożnością nadpisania lepszy jest ten singleton od globala? smile.gif
sannin
Trochę poczytałem, nie wiem czy zrozumiałem ;d ale zrobiłem tak:

do każdej klasy dodałem na początku

Kod
private static $objInstance = null;
     private $intValue = null;
     ########################################################
     private function __construct() {
         $this->intValue = rand(1, 100);
     }
     ########################################################
     public static function create() {
         if (is_null(self::$objInstance)) {
             self::$objInstance = new self();
         }
         return self::$objInstance;
     }
     ########################################################


Później wywołuje to tak
Kod
$Mysql = MySql::Create();
$Mysql->Connect($CONFIG['dbHost'], $CONFIG['dbUser'], $CONFIG['dbPassword'], $CONFIG['dbName']);
$Mysql->metoda();


W klasach muszę natomiast robić tak

Kod
MySql::selectToArray()
Czy może mi to kotś wytłumaczyć smile.gif?
erix
Cytat
Tak jak chociażby Mize powiedział, nie mogę np. w widoku wykonywać zapytań do bazy danych

Yyyyy... W widoku zapytania do bazy...? My mamy nadal na myśli MVC, czy mam w czymś braki?

Cytat
No i wszystko mam w jednym miejscu, co daje pewien porządek.

No z tym się zgodzę.

Cytat
poza niemożnością nadpisania lepszy jest ten singleton od globala?

Właśnie ta niemożność nadpisania. tongue.gif Poza tym, łatwiej jest znaleźć deklarację obiektu, do którego się singleton odnosi. A w przypadku global szukaj wiatru w polu.

Osobiście korzystam z pewnego rodzaju "hybrydy"; wyznaję zasadę, że co jest wygodniejsze+wydajniejsze w użyciu. winksmiley.jpg
sannin
Czy jest ktoś w stanie mi pomóc zamiast się wykłócać?
erix
Cytat
W klasach muszę natomiast robić tak

A zwykła konstrukcja create nie działa...? Nie wiem, jaką masz deklarację selectToArray...

PS. Poprosiłem już o wydzielenie wątku, jak coś.
sannin
Działa, tylko że wtedy muszę od nowa łączyć się z mysql. Chciałbym, zeby coś takiego w pliku system.php

Kod
require('library.php');
require('config.php');
$mysql = MySql::Create();
$mysql->connect($CONFIG['dbHost'], $CONFIG['dbUser'], $CONFIG['dbPassword'], $CONFIG['dbName']);


Załatwiało sprawę połączenia. Później daje tylko $index->prace() w której mam selectToArray

Później mam wykonywać metody MySql::metoda czy $mysql->metoda ?
erix
Później $mysql->metoda. Z dwukropkiem wywołujesz tylko metody oznaczone frazą static" title="Zobacz w manualu PHP" target="_manual w deklaracji.

Troszkę mało informacji podałeś, np. jak wywołujesz selectToArray.
sannin
Poczytałem i wydaje mi się, że już to łapie... Dosyć pomocy był ten wpis http://athlan.pl/singleton-registry-map/ tylko autor pisze tutaj, że singleton nie jest najlepszym rozwiązaniem, ale przeszukują fora widzę, że jest to kwestia bardzo sporna które rozwiązanie jest najlepsze... Robię tak... do każdej klasy dodaje

Kod
private function __construct() {
         }
         ########################################################
         public static function instance() {
             if(!self::$_oInstance instanceof self) {
                 self::$_oInstance = new self;
             }        
             return self::$_oInstance;
         }
Później wystarczy tylko
Kod
$mysql = MySql::instance();
             $zmienna = $mysql->metoda()
Z tego co rozumiem to MySql::instance(); Utworzy obiekt, a jeśli istnieje to go zwróci, dzięki temu mogę działać tą klasą po całym "systemie" bez obaw i nie muszę się martwić nadpisaniem i mam pewność, że zawsze korzystam z tego samego wywołania obiektu. Czy dobrze to rozumiem i czy jest to dobre (nienajlepsze) rozwiązanie na używanie obiektowego php? Odchodząc od tematu mam jeszcze pytanie co do config.php w którym są przetrzymywane zmienne systemowe. Czy wstawiać tam stałe, żeby były dostępne wszędzie czy zmienne i wczytywać w funkcji jak globalne? Czy może jeszcze jakoś inaczej?
erix
Cytat
tylko autor pisze tutaj, że singleton nie jest najlepszym rozwiązaniem, ale przeszukują fora widzę, że jest to kwestia bardzo sporna

Między innymi dlatego wynikł offtop w tym temacie. ;P

Cytat
Z tego co rozumiem to MySql::instance(); Utworzy obiekt, a jeśli istnieje to go zwróci, dzięki temu mogę działać tą klasą po całym "systemie" bez obaw i nie muszę się martwić nadpisaniem i mam pewność, że zawsze korzystam z tego samego wywołania obiektu.

Czyli dobrze zrozumiałeś. winksmiley.jpg

Cytat
Czy wstawiać tam stałe, żeby były dostępne wszędzie czy zmienne i wczytywać w funkcji jak globalne? Czy może jeszcze jakoś inaczej?

Hmm, to kwestia tak samo sporna, jak wyżej. Choć powstały pewne niepisane zasady, jak np. trzymanie ścieżek do katalogów aplikacji w stałych, itp. Przejrzyj sobie źródła paru skryptów (mam na myśli skryptów, a nie jakichś beznadziejnych "systemów" newsowych pisanych przez samozwańczych "programistów"), to sam wyciągniesz wnioski.
l0ud
Cytat
Odchodząc od tematu mam jeszcze pytanie co do config.php w którym są przetrzymywane zmienne systemowe. Czy wstawiać tam stałe, żeby były dostępne wszędzie czy zmienne i wczytywać w funkcji jak globalne? Czy może jeszcze jakoś inaczej?


Jeżeli chodzi o mnie, to w takim pliku definiuję kilka stałych, które są niezbędne do zainicjowania właściwego obiektu, który zajmuje się konfiguracją i wczytuje wartości z bazy oraz które wystarczą do w miarę eleganckiego obsłużenia błędu, jeżeli coś się posypie. Z reguły są to dane do bazy oraz ścieżki do poszczególnych folderów. Czasem umieszczę jakąś wartość, której nie planuję zmieniać przez panel administracyjny, a która może się przydać przy późniejszej przebudowie skryptu. Takie rzeczy jednak, jak np. ilość elementów na stronie (do paginacji) trzymam już w bazie, z możliwością zmiany w PA smile.gif
sannin
Cytat(l0ud @ 21.11.2008, 22:40:45 ) *
Takie rzeczy jednak, jak np. ilość elementów na stronie (do paginacji) trzymam już w bazie, z możliwością zmiany w PA smile.gif


Tak robię, bardziej chodziło mi o adres email admina itd. W sumie mam taki pomysł na to, w pliku config.php trzymam tylko dane do połączenie z mysql. Tworzę sobie klasę o nazwie Config która będzie pobierała z mysql wszystkie inne wartości. Dzięki temu będę miał do nich dostęp wszędzie i możliwość edycji z PA. Czy jest to dobre rozwiązanie smile.gif?
erix
To już jak Tobie wygodniej. winksmiley.jpg

Choć dobrym sposobem jest inicjowanie połączenia bezpośrednio z pliku konfiguracyjnego, gdyż dane do SQL nie są przechowywane w zmiennych i nie można ich już tak łatwo odczytać.
adek140
Cytat(l0ud @ 20.11.2008, 20:59:13 ) *
core.php
  1. <?php
  2. class core {
  3.   private $obj = array();
  4.  
  5.   public function __get($objName) {
  6.      if (isset($this->obj[$objName])) return $this->obj[$objName];
  7.   }
  8.  
  9.   public function load($className) {
  10.      include('includes/'.$className.'.php');
  11.      $this->obj[$className] = new $obj($this);
  12.   }
  13.  
  14.  public function initComponents() {
  15.     $this->load('mysql');
  16.      $this->load('config'); //itd
  17.  }
  18.  
  19. }
  20. ?>


12 linijka w pliku powyżej powoduje błąd sad.gif
Fatal error: Class name must be a valid object or a string in H:\Serwer\tescik\includes\core.php on line 11

jakaś wskazówka?
tutaj pliczki http://wyslijto.pl/plik/u0rcn5sg8s
TrevorGryffits
No tak. A gdzie deklarujesz zmienną $obj?
Fifi209
Cytat(adek140 @ 31.07.2009, 15:49:11 ) *
12 linijka w pliku powyżej powoduje błąd sad.gif
Fatal error: Class name must be a valid object or a string in H:\Serwer\tescik\includes\core.php on line 11

jakaś wskazówka?
tutaj pliczki http://wyslijto.pl/plik/u0rcn5sg8s


Jeżeli Ci to pomoże, mam coś podobnego w swoim prototypowym widoku:

  1. <?php
  2. public function __get($name) {
  3.            if ($this->modules[$name]) {
  4.                return $this->modules[$name];
  5.            }else{
  6.                return false;
  7.            }
  8.        }
  9.  
  10.        public function _load($name) {
  11.            if ($this->$name) {
  12.                return $this->$name;
  13.            }else{
  14.                $temp = __CLASS__ .'_'. $name;
  15.                if (file_exists('modules/'.$temp.'.php')) {
  16.                    include_once('modules/'.$temp.'.php');
  17.                    return $this->$name = new $temp;
  18.                }else{
  19.                    return false;
  20.                }
  21.            }
  22.        }
  23. ?>


Oczywiście to wycięty fragment.
Uznałem, że podzielenie widoku na moduły odpowiadające np. za szablony, bbcode, formularze będzie dobrym rozwiązaniem. (mam wszystko ładnie posegregowane i wiem co do czego jest)

Sam plik z tą klasą nazywa się view.php
A moduły przykładowo: view_template.php (który zawiera klasę o takiej samej nazwie)

Działa i powiem, że dość fajne rozwiązanie na które po części naprowadził mnie Erix (mój pro haha.gif) . smile.gif
adek140
niestety wciąż nie potrafie sobie poradzić sad.gif

przedstawie wszystko od początku

index.php
  1. <?php
  2.  
  3. include ('includes/core.php');
  4.  
  5. $core = new core;
  6. $core->initComponents();
  7.  
  8. $core->config->test();
  9.  
  10.  
  11. ?>


includes/core.php
  1. <?php
  2.  
  3. class core
  4. {
  5.  
  6. public function _load($name)
  7. {
  8. include_once('includes/'.$name.'.php');
  9. $this->$name = new $name($core);
  10. }
  11.  
  12. public function initComponents()
  13. {
  14. $this->_load('config');
  15. $this->_load('maile');
  16. }
  17. }
  18.  
  19. ?>


includes/config.php
  1. <?php
  2. class config {
  3.  
  4. private $maile;
  5.  
  6. public function __construct($core) {
  7. $this->maile = $core->maile;
  8. }
  9.  
  10. public function test() {
  11. echo 'krok 1 z klasy config <br>';
  12. $this->maile->test2();
  13. }
  14. }
  15. ?>


includes/maile.php
  1. <?php
  2. class maile
  3. {
  4. private $config;
  5.  
  6. public function __construct($core)
  7. {
  8. $this->config = $core->config;
  9. }
  10.  
  11. public function test2()
  12. {
  13. echo 'krok 2 z klasy maile';
  14. }
  15. }
  16. ?>


efekt

Kod
krok 1 z klasy config

Fatal error: Call to a member function test2() on a non-object in H:\Serwer\tescik\includes\config.php on line 12


mógłby mi ktoś podpowiedzieć gdzie popełniam błąd? domyślam się, że w którymś miejscu przy przekazywaniu obiektu core, ale, jak pisałem, jestem początkujący i nie potrafię sam sobie z tym poradzić, mimo wielu prób metodą 'prób i błędów'

pozdrawiam worriedsmiley.gif
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.