Наследование классов, факторизация кода, объектная модель php - PullRequest
2 голосов
/ 31 января 2012

Скажем, у меня есть абстрактный класс Entity, у меня также есть несколько абстрактных классов Provider, Model, Service, ... все это расширяет непосредственно Entity.Наконец, у меня есть последний набор конкретных классов ConcreteProvider, ConcreteModel, ..., который расширяет соответственно Provider, Model, ...

На каждом экземпляре Concrete * я хочу метод getId (), который при вызовеэкземпляр класса, который расширяет Provider (например, ConcreteProvider), он возвращает строку «Provider» и т. д. для Model и ...

Единственный способ, который я нашел для достижения этой цели:

abstract class Entity {
    abstract function getId ();
}

abstract class Provider extends Entity {
    function getId () {
        return __CLASS__;
    }
}

abstract class Model extends Entity {
    function getId () {
        return __CLASS__;
    }
}

class ConcreteProvider extends Provider {
}

class ConcreteModel extends Model {
}

$cp = new ConcreteProvider();
echo $cp->getId() . "\n"; // returns the string Provider
$cm = new ConcreteModel();
echo $cm->getId(); // returns the string Model

Дублирование кода здесь очевидно.Я ищу то же самое поведение без дубликатов.Думаю, было бы неплохо поместить метод в Entity.

У вас есть идея?Как бы вы это сделали?

// Edit

Конечно, есть способ переместить getId в Entity:

abstract class Entity {
    function getId () {
      $class = get_called_class();
      while ( __CLASS__ !== get_parent_class($class) )
        $class = get_parent_class($class);
      return $class;
    }
}

Но есть много вычисленийИбо, ничего, ничего не стоит ...

Ответы [ 5 ]

2 голосов
/ 31 января 2012

Я не большой поклонник магии, поэтому я рекомендую прямой путь

const ID = 'Provider';
public function getId () {
    return self::ID;
}

Или просто

function getId () {
    return 'Provider';
}

, но с константой легче сравнивать

$x->getId() == Provider::ID;
1 голос
/ 22 июля 2012

Вот лучшее, что я нашел, используя мое второе предложение и добавив к нему памятку.

abstract class Entity {
    private $subType = '';
    function getId () {
      if ( $this->subtype )
        return $this->subType;
      $class = get_called_class();
      while ( __CLASS__ !== get_parent_class($class) )
        $class = get_parent_class($class);
      return $this->subType = $class;
    }
}
0 голосов
/ 31 января 2012

Вы должны использовать магический метод PHP __toString () для классов, для которых вы хотите получить имена классов, затем, когда вы приведете объект в виде строки, он вернет имя класса:

abstract class Provider extends Entity {
    public function __toString() {
        return __CLASS__;
    }
}

abstract class Model extends Entity {
    public function __toString() {
        return __CLASS__;
    }
}

$cp = new ConcreteProvider();

var_dump($cp); // Outputs object

// Force cast of $cp object to a string, which calls __toString()
var_dump((string) $cp); // Outputs Provider

// Vanilla echo forces object cast to string
echo $cp; //Outputs Provider

$cm = new ConcreteModel();

var_dump($cm); // Outputs object

// Force cast of $cp object to a string, which calls __toString()
var_dump((string) $cm); // Outputs Model

// Vanilla echo forces object cast to string
echo $cm; 

При таком подходе вам не нужно навязывать метод getId дочерним классам, расширяющим родительский класс Entity.

Кроме того, использование getId() для этой функции неправильно.ведущий imo, в 99% случаев, когда я вызываю метод classe getId(), я ожидаю int, представляющий конкретный экземпляр объекта, извлеченный из хранилища (база данных, кэш, плоский файл).

0 голосов
/ 31 января 2012
<?php
class Entity {
  public static function getId() {
    return get_called_class();
  }
}


class Model extends Entity {

}

class Provider extends Entity {

}

$a = new Model();
echo $a->getId(); //returns Model

$b = new Provider();
echo $b->getId(); //returns Provider

$c = new Entity();
echo $c->getId(); //returns Entity

Использование позднего статического связывания.Ваша версия php должна быть больше 5.3.

http://www.php.net/manual/en/function.get-called-class.php

0 голосов
/ 31 января 2012

Обновление 2014:

Если вы используете PHP 5.4+, вы можете использовать trait , чтобы разделить эту функцию между моделями и поставщиками.


Что мешает вам использовать систему типов?Где вы в данный момент можете позвонить:

if ($object->getId() == 'Provider') {
    // provider specific code
}

Не можете ли вы использовать:

if ($object instanceof Provider) {
    // provider specific code
}

По общему признанию, использование таких условных выражений отрицает цель полиморфизма.Я мог бы предложить лучший совет с большим контекстом.

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