Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Object-oriented programming _ Ciekawostka - static w abstract calss

Napisany przez: markuz 28.01.2017, 19:07:02

Ostatnio spotkałem się z ciekawym "bugiem" który podobno nim nie jest. Ciekawy jestem jakie jest Wasze zdanie na ten temat.

Mam kod:

  1. <?php
  2.  
  3. interface A
  4. {
  5. http://www.php.net/static function create();
  6. }
  7.  
  8. abstract class B implements A
  9. {
  10.  
  11. protected http://www.php.net/static $instance;
  12.  
  13. protected function __construct()
  14. {
  15. }
  16.  
  17. public http://www.php.net/static function getInstance()
  18. {
  19. if (http://www.php.net/static::$instance === null) {
  20. http://www.php.net/static::$instance = http://www.php.net/static::create();
  21. }
  22.  
  23. return http://www.php.net/static::$instance;
  24. }
  25. }
  26.  
  27. class C {
  28.  
  29. private $number;
  30.  
  31. public function __construct($number) {
  32. $this->number = $number;
  33. }
  34.  
  35. public function getNumber() {
  36. return $this->number;
  37. }
  38.  
  39. }
  40.  
  41. class D extends B {
  42.  
  43. http://www.php.net/static function create() {
  44. return new C(1);
  45. }
  46.  
  47. }
  48.  
  49. class G extends B {
  50.  
  51. http://www.php.net/static function create() {
  52. return new C(2);
  53. }
  54.  
  55. }
  56.  
  57. http://www.php.net/echo "a = " . D::getInstance()->getNumber() . PHP_EOL;
  58. http://www.php.net/echo "b = " . G::getInstance()->getNumber() . PHP_EOL;


Jakie Twoim zdaniem wartości powinno mieć a i b? (fajnie jakbyś nie wykonywał tego kodu przed odpowiedzią)

Następnie do powyższego kodu dodamy 3 nowe klasy:

  1. abstract class F implements A
  2. {
  3.  
  4. protected http://www.php.net/static $instance;
  5.  
  6. protected function __construct()
  7. {
  8. }
  9.  
  10. public http://www.php.net/static function getInstance()
  11. {
  12. if (http://www.php.net/static::$instance === null) {
  13. $t = '';
  14. http://www.php.net/static::$instance =& $t;
  15. http://www.php.net/static::$instance = http://www.php.net/static::create();
  16. }
  17.  
  18. return http://www.php.net/static::$instance;
  19. }
  20. }
  21.  
  22. class E extends F {
  23.  
  24. http://www.php.net/static function create() {
  25. return new C(3);
  26. }
  27.  
  28. }
  29.  
  30. class H extends F {
  31.  
  32. http://www.php.net/static function create() {
  33. return new C(4);
  34. }
  35.  
  36. }
  37.  
  38. http://www.php.net/echo "c = " . E::getInstance()->getNumber() . PHP_EOL;
  39. http://www.php.net/echo "d = " . H::getInstance()->getNumber() . PHP_EOL;


Jakie wartości będzie mieć c i d?

Jak wiadomo static użyte w klasie powinno kierować do "ostatniej" w hierarchii klasy. Jednak static w klasach abstrakcyjnych wydaje się być jakimś innym tworem - być może dlatego, że self w takich klasach nie może istnieć. Jeżeli zrobimy jednak zabieg z klasy F w getInstance static znowu jest tym "normalnym" static. Przez normalnym mam na myśli zachowanie które uważam za prawidłowe - obiekt klasy abstrakcyjnej nie może istnieć dlaczego więc static klasy abstrakcyjniej może?

Tym sposobem możemy też sprawić aby static nie był static w zwykłych klasach:

  1. <?php
  2.  
  3. class B {
  4.  
  5. http://www.php.net/static $number;
  6.  
  7. }
  8.  
  9. class C extends B {
  10.  
  11. }
  12.  
  13. class G extends B {
  14.  
  15. }
  16.  
  17. B::$number = 5;
  18. http://www.php.net/echo C::$number . PHP_EOL;
  19. http://www.php.net/echo G::$number . PHP_EOL;
  20. C::$number = 2;
  21. http://www.php.net/echo C::$number . PHP_EOL;
  22. http://www.php.net/echo G::$number . PHP_EOL;
  23. $t = 11;
  24. C::$number =& $t;
  25. http://www.php.net/echo C::$number . PHP_EOL;
  26. http://www.php.net/echo G::$number . PHP_EOL;

Napisany przez: adbacz 6.02.2017, 14:38:31

Static odnosi się do klasy jako kontenera, a nie do obiektu tej klasy. Klasa abstrakcyjna daje możliwość utworzenia "tak jakby" interfejsu, już z predefiniowanymi metodami, które klasa dziedzicząca wspóldzieli. Odwołania statyczne do klasy mają się nijak do tworzenia obiektów. Dlatego static::$zmienna działa dla klasy abstrakcyjnej. A to, do której ona klasy należy, to już zależy od dziedziczenia. Powinno się używać static od klasy w której jest to zdefiniowane.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)