ООП / PHP5: вызов класса A из класса B - или прыжок с лошади - PullRequest
0 голосов
/ 13 сентября 2009

Скажем, у вас есть два класса, A и B. Возможно ли создать экземпляр обоих классов один раз, а затем позволить классу B вызывать методы в классе A, и наоборот?

Это можно сделать, используя двойное двоеточие (::) ... ... но тогда метод становится статичным - это недостаток? (см. пример ниже)

Можно ли это сделать другими способами? С интерфейсами?

Этот код показывает, что я пытаюсь сделать:

class A {
  function horse() {
    echo "horse";
  }
}

class B {
  function jump() {
    // $A = new A; ... don't want to add this in each method.
    $A->horse();  // Fails - $A is out of scope ($A = new A;).
    // A::horse();  // Old code style - works.
    // $this->horse();  // Works if you extend A - not self-documenting.
    // $this->A->horse();  // Fails - out of scope.
  }
}

$A = new A;
$B = new B; // Better to use "$B = new B($A);" ?
$B->jump(); // fails - the horse is sleeping.

Редактировать

Что ж, я строю MVC-фреймворк и хочу повторно использовать код из других классов. Некоторые примеры из реальной жизни:

  • объект базы данных, который передается через классы.
  • класс "url", который создает / манипулирует URL-адресами - используется другими классами.
  • ... и пример кода:

    class url {
        function anchor($url,$name) {
            return "<a href="{$url}\">{$name}</a>";
        }
    }
    
    class someclass {
        function text($str,$url) {
            return "{$str}. " . $url->anchor($url,"Read more...");
        }
    }
    

Ответы [ 4 ]

1 голос
/ 13 сентября 2009

Я думаю, что вы просите множественное наследование, где вы могли бы расширить как A, так и B следующим образом

<?php
class C extends A,B {

//...

}

Это, однако, не возможно в PHP по веским причинам (на самом деле это создает больше проблем, чем пытается решить).

Теперь вы можете спросить себя, есть ли альтернатива множественному наследованию, и ответ: да, есть! Взгляните на шаблон стратегии (как также указал Бенджамин Ортузар).

UPDATE

Я только что прочитал ваш вопрос во второй раз и подумал, что вы можете искать одноэлементный шаблон , который позволяет вам создавать экземпляр класса только один раз, например так:

class A
{

    protected static $_instance;

    protected function __construct() //prohibit creating instances from outside
    { }

    public static function getInstance() 
    {
      if( self::$_instance === NULL ) {
        self::$_instance = new self();
      }
      return self::$_instance;
    }
}

$instance = A::getInstance();

Теперь A::getInstance() всегда возвращает один и тот же экземпляр A, который вы можете использовать в B, и вы можете иметь как преимущества динамических функций, так и доступность статических функций.

UPDATE2

Ваша база данных принадлежит реестру , если вы можете иметь более одного db-соединения. Если вы абсолютно уверены, что вам всегда понадобится только одно db-соединение, вы можете сделать его одиночным.

Для помощника по URL я бы предложил написать статический класс, если вы можете, и если вам действительно нужно, чтобы он был динамическим, сделайте его одиночным, как упоминалось ранее.

0 голосов
/ 13 сентября 2009

Может быть (просто догадываясь), вы ищете что-то вроде агрегации в COM :

Агрегация - это механизм повторного использования объекта, в котором внешний объект предоставляет интерфейсы от внутреннего объекта, как если бы они были реализованы на самом внешнем объекте.

Вы можете создать нечто подобное с помощью "магического метода" __call . Каждый раз, когда вызывается метод, который не вызывается в контексте объекта, этот метод вызывается, и ваш код может решить, что делать с этим вызовом. Например. он может проверить, предоставляет ли другой объект, который хранится как свойство «внешнего» объекта, метод с этим именем и затем вызывает метод этого внутреннего объекта.

class Foo {
  protected $inner = null;
  public function __construct($inner=null) {
    if ( is_null($inner) && !is_object($inner) ) {
      throw new Exception('...');
    }
    $this->inner = $inner;
  }

  public function __call($name, $arguments) {
    // also check http://uk.php.net/is_callable
    if ( !is_null($this->inner) && method_exists($this->inner, $name) ) {
      return call_user_func_array( array($this->inner, $name), $arguments);
    }
    else {
      // add some error handler here
      throw new Exception('...');
    }
  }

  function jump() {
    $this->horse();
    echo " jumps";
  }
}

class Bar {
  function horse() {
    echo "horse";
  }
}

$foo = new Foo(new Bar);
$foo->jump();

Это работает. Но я бы порекомендовал что-то подобное только для определенных обстоятельств. Самая очевидная причина заключается в том, что извне трудно сказать, что этот объект $ foo действительно может и не может делать.

0 голосов
/ 13 сентября 2009

Я бы посоветовал прочитать о фабрике и стратегии. Вы можете прочитать об этом больше в первой главе этой фантастической книги. текст ссылки

Я бы рекомендовал вам прочитать всю книгу.

0 голосов
/ 13 сентября 2009

Я думаю, что это должно работать:

$B = new B();
$B->jump();

Но вы должны прочитать / обратиться к http://www.php.net/manual/en/language.oop5.php

Конечно, вы должны импортировать класс, если вы обращаетесь к нему из другого php-файла. И если вы находитесь в объекте, который вызываете, метод, который вы используете, должен использовать

$this->jump();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...