Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]konstruktor
Forum PHP.pl > Forum > Przedszkole
twojastara
uczę się. Dlaczego konstruktor w wersji drugiej wywala komunikat Error: Call to a member function get() on a non-object
1.
  1. namespace AppBundle\Utils;
  2.  
  3.  
  4. class Cart {
  5.  
  6. public $request;
  7. public $session;
  8. public $cart;
  9.  
  10. public function __construct(Request $request)
  11. {
  12. $this->request = $request;
  13. $this->session = $this->request->getSession();
  14. $this->cart = $this->session->get('cart');
  15. }
  16. }


  1. $cart_obiekt = new Cart($request);

2.

  1. namespace AppBundle\Utils;
  2. use Symfony\Component\HttpFoundation\Request;
  3.  
  4. class Cart {
  5.  
  6. public $request;
  7. public $session;
  8. public $cart;
  9.  
  10. public function __construct()
  11. {
  12. $this->request = new Request();
  13. $this->session = $this->request->getSession();
  14. $this->cart = $this->session->get('cart');
  15. }
  16. }

  1. $cart_obiekt = new Cart();
Mariner
Ponieważ $this->request->getSession() nie zwraca obiektu. Sprawdź co zwraca. Jest to związane ze sposobem w jaki przypisywany jest obiekt $request. W pierwszej wersji z zewnątrz, a więc możemy się domyślać że jest zainicjowany i posiada już przypisany obiekt session. W drugim przypadku obiekt Request tworzony jest w kontrolerze a więc nie posiada danych żądania ani session.
twojastara
Cytat(Mariner @ 16.03.2015, 20:08:23 ) *
Ponieważ $this->request->getSession() nie zwraca obiektu.

a dlaczego ma znaczenie co zwraca?

Dla ścisłości
Error: Call to a member function get() on a non-object
wywala dla lini nr 14.
  1. $this->cart = $this->session->get('cart');



a w ogóle jak sensownie przetłumaczyć ten komunikat na polski?
Aqu
Odwołujesz się tutaj do metody get, więc $this->session musi być obiektem, a $this->request->getSession(); widocznie Ci tego nie zwraca.
Damonsson
Mniej więcej tłumaczenie tak czytaj: Odwołujesz się do metody get(), w czymś ($this->session) co nie jest obiektem(, więc nie może zawierać żadnych metod).

W przypadku 1. przekazujesz zawartość obiektu $request do konstruktora. W przypadku 2. tworzysz nowy obiekt $request, który nie ma pojęcia o istnieniu sesji.
twojastara
acha,

no tak, Mariner w pierwszej odpowiedzi pisał coś podobnego, (ale zamiast 'w konstruktorze' napisał 'w kontrolerze').

Rozumiem już komunikat i dlaczego się pojawia, ale nie bardzo rozumiem dlaczego 'nie ma pojecia o istnieniu sesji', no chyba na tym polega sesja, że jest widoczna wszędzie.

faktycznie $cart_obiekt = new Cart(); print_r($cart_obiekt->session) nic nie zwraca przy drugiej wersji.

"W przypadku 2. tworzysz nowy obiekt $request, który nie ma pojęcia o istnieniu sesji. "

nie pojmuję dlaczego ten obiekt nie widzi sesji.
Damonsson
Bo tworzysz nowy obiekt new Request() w którym normalnie jest zawsze trzymana sesja. W którym nic nie ma, sesja jest równa null. W Symfony nie masz dostępnej superglobalnej zmiennej $_SESSION dostępnej z każdego miejsca, tylko odwołujesz się bodajże zawsze do Request().
Mariner
Cytat(twojastara @ 16.03.2015, 22:49:56 ) *
a dlaczego ma znaczenie co zwraca?

Dla ścisłości
Kod
Error: Call to a member function get() on a non-object
wywala dla lini nr 14.


Ponieważ w następnej linii, właśnie nr. 14, używasz składowej session tak jak obiektu, wywołując na niej metodę get('cart'). Jak zapewne wiesz, nie można wywołać metody na zmiennej która nie przechowuje w sobie obiektu a taka próba kończy się błędem.

Powinieneś wstrzyknąć obiekt klasy Request już gotowy z zewnątrz, dokładnie tak jak w pierwszym przypadku a nie tworzyć go od nowa w konstruktorze ponieważ wtedy będzie pusty i zwracał będzie puste wartości. W drugim przypadku, sposób pozyskiwania obiektu klasy Request sprawia że jest on pusty. Nie możesz oczekiwać że już samo utworzenie obiektu Request sprawi że będzie miał on w sobie dane które może Ci zwrócić.

W systemie Symfony, obiekt Request możesz pozyskać z kontenera $request = $container->get('request'). Jeżeli masz problem z dostępem do obiektu Request w klasie Card, spraw aby obiekty klasy Cart tworzone były jako usługi (services). Przykładowy plik services.xml mógłby wyglądać tak:

CODE
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/ser...0.xsd">

<services>

<service id="app_utils.card.service" class="\AppBundle\Util\Card">
<argument type="service" id="request"/>
</service>

</services>
</container>


Dzięki temu, w kontrolerach, obiekty klasy Cart możemy pozyskiwać tak $card = $this->get('app_utils.card.service') o ile klasę Card zadeklarujesz jak w pierwszym przykładzie.
A za powoływanie obiektów klasy Card i wstrzykiwanie im obiektu Request martwił będzie się kontener zależności Symfony.

Cytat(twojastara @ 16.03.2015, 23:28:47 ) *
acha,

no tak, Mariner w pierwszej odpowiedzi pisał coś podobnego, (ale zamiast 'w konstruktorze' napisał 'w kontrolerze').


Fakt. Mój błąd, chodziło oczywiście o konstruktor a nie kontroler.
Damonsson
Na chłopski rozum:

Masz pudełko w którym trzymasz batonika. Zamiast wrzucić przez okno to pudełko z batonikiem. Ty kupujesz nowe puste pudełko, wrzucasz je przez okno i dziwisz się, że nie ma w nim batonika.
twojastara
dzięki Wam obu.

Tylko, że ja wcale nie uważam by to pudełko w pierwszej wersji miało w środku jakiegoś batona.

W pierwszej wersji jakos specjalnie nie staram się by inicjować obiekt Cart z parametrem ... z batonem.

(Za 2 minuty edytuję ten post ze szczegółami)

bo w pierwszej wersji inicjalizacja obiektu Cart wygląda tak:

w kontrolerze w akcji

  1.  
  2. use Symfony\Bundle\FrameworkBundle\Controller\Controller;
  3. use Symfony\Component\HttpFoundation\Request;
  4. use AppBundle\Utils\Cart;
  5.  
  6. public function test1Action(Request $request)
  7. {
  8. $cart_obiekt = new Cart($request);
  9.  
  10.  
  11. return array();
  12. }


I tę akcję inicjuję jako pierwszą, tj. obiekt request jest tutaj pierwszy raz powoływany.


Wychodzi na to, że nie rozumiem podstaw zwiazanych z inicjowaniem zmiennych/obiektów. Sądziłem, że taki zapis
  1. function test1Action(Request $request)
równy jest takiemu
  1. function test1Action(){$request= new Request();}
Damonsson
Symfony robi to za Ciebie. Sprawdź:

  1. namespace AppBundle\Utils;
  2.  
  3.  
  4. class Cart {
  5.  
  6. public $request;
  7. public $session;
  8. public $cart;
  9.  
  10. public function __construct(Request $request)
  11. {
  12. echo '<pre>';
  13. var_dump($request);
  14. die;
  15. $this->request = $request;
  16. $this->session = $this->request->getSession();
  17. $this->cart = $this->session->get('cart');
  18. }
  19. }


poiwnno być w środku session



Edit: Nie korzystam z Symfony, więc szczegółowo Ci nie powiem, ale prześledź sobie jakimś XDEBUG co się dzieje po kolei w kodzie i zobaczysz, że gdzieś tam na samym początku jest tworzony nowy obiekt Request() i później jest tylko PRZEKAZYWANY ciągle ten sam obiekt, wszędzie.


  1. function test1Action(Request $request)

Tu przekazujesz zmienną $request, która musi być instancją obiektu(czy jakkolwiek to fachowo nazwać) Request().

  1. function test1Action(){$request= new Request();}

Tutaj tworzysz nowy obiekt Request().
twojastara
tak, to już przekonałes mnie wcześniej.

Muszę się zadowolić tłumaczeniem, że Symfony jakoś tam robi za mnie.


że powołowanie do życia $request = new Request(); ma inną zawartość w kontrolerze i innej/zwykłej klasie.
----

edit

Takie wytłumaczenie mi wystraczy. Dzięki za poświęcony czas!
Mariner
Obiekty Request w kontrolerach Symfony2 są tak często używane że zdecydowano się uprościć programistom sprawę z ich pozyskiwaniem w kontrolerach. Dlatego jeżeli zadeklarujesz obiekt request w parametrach metody to otrzymasz gotowy obiekt wypełniony danymi. Nie trzeba chyba wyjaśniać że normalnie tak to nie działa.

To nie jest tak że w Symfony konstrukcja new Request() nie jest tożsama jak w php. Obiekty są tworzone tak samo, z tym że obiekt Request w Symfony2, zanim go otrzymasz, w metodzie kontrolera wypełniany jest przez framework danymi z żądania. Tu nie ma żadnej "magii".
twojastara
Cytat(Damonsson @ 17.03.2015, 00:03:17 ) *
  1. function test1Action(Request $request)

Tu przekazujesz zmienną $request, która musi być instancją obiektu(czy jakkolwiek to fachowo nazwać) Request().

Recz w tym, że to pierwsza i jedyna funkcja w tej przykładowej aplikacji, że wcześniej zmienna $request nie jest nigdzie manipulowana, więc to tu obiekt $request jest powoływany do ż.

Cytat(Mariner @ 17.03.2015, 00:26:00 ) *
Tu nie ma żadnej "magii".

Dzięki. Wszystko już wystarczająco jasne.
Mariner
Cytat(twojastara @ 17.03.2015, 00:29:04 ) *
Recz w tym, że to pierwsza i jedyna funkcja w tej przykładowej aplikacji, że wcześniej zmienna $request nie jest nigdzie manipulowana, więc to tu obiekt $request jest powoływany do ż.


Framework Symfony2 używa Twojego kontrolera w taki mniej więcej sposób:

CODE
$request = new Request();

$request->bind($_POST, $_GET);

$controller = new YourController();

$response = $controller->test1Action($request);


Tylko tak teraz patrzę w Twój kod ale nie widzę tam kontrolera tylko funkcję. Czy u Ciebie kontroler jest obiektem klasy Controller?
twojastara
Cytat(Mariner @ 17.03.2015, 00:35:42 ) *
Tylko tak teraz patrzę w Twój kod ale nie widzę tam kontrolera tylko funkcję. Czy u Ciebie kontroler jest obiektem klasy Controller?

tak, ta funkcja/akcja jest wewnątrz:
  1. class CartController extends Controller
  2. {
Mariner
Wybacz to pytanie ale lepiej się upewnić. Jeżeli coś jeszcze mogę doradzić to tak jak polecał kolega wcześniej, żeby zrozumieć lepiej działanie symfony, dobrze jest choć raz prześledzić pracę całego programu. Jeżeli nie masz do zainstaluj xdebug oraz ide którym będziesz mógł debugować skrypty i na bieżąco śledzić czy nawet zatrzymywać pracę programu w dowolnym momencie. Być może na początku wydawać by się to mogło trudną sprawą ale wiedz że wcześniej czy później i tak tego nie unikniesz. Im szybciej się na to zdecydujesz tym lepiej dla Ciebie. Ze swojej strony mogę polecić eclipse z php dev doinstaluj xdebuga, czego nie będziesz wiedział zapytaj na forum. Naprawdę warto. Polecam i pozdrawiam.
twojastara
tak, już przy wcześniejszym poście dot. xdebug zaznaczyłem sobie, by jutro szczegółowo sie temu przyglądnąć.

Korzystam z netbeans, więc będę szukał coś pod niego. (Jeszcze raz dzięki, kupe wartościowej dla mnie treści w tym temacie)
com
Poczytaj o depedency injection a zrozumiesz czemu to tak działa smile.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.