tostring — несколько PHP-методов __toString, переключаемых во время выполнения

Мне нужны разные __toString() для того же класса.

У меня есть класс Person, который содержит имя и фамилию. В соответствии с текущим контекстом я хочу отобразить его в другом порядке, форматировании и т. Д. Представьте три сценария:

  • на первом месте имя, затем пробел и фамилия Thomas Müller
  • фамилия идет первой и заглавной, затем пробел и имя MÜLLER Thomas
  • сначала идет фамилия, затем запятая, затем пробел и имя Müller, Thomas

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

<meta charset='utf-8'/>
<?php
class Person
{
protected $firstname;
protected $surname;

public function __construct($firstname, $surname)
{
$this->firstname = $firstname;
$this->surname = $surname;
}

public function toStringWithFirstnameFirst()
{
return $this->firstname . " " . $this->surname;
}

public function toStringWithSurnameFirstUppercase()
{
$surnameConverted = mb_convert_case($this->surname, MB_CASE_UPPER, "UTF-8");
return $surnameConverted . " " . $this->firstname;
}

public function toStringWithSurnameFirstAndFirstnameAfterComma()
{
return $this->surname . ", " . $this->firstname;
}
}

$person = new Person("Thomas", "Müller");
echo $person->toStringWithFirstnameFirst() . "<br/>";
echo $person->toStringWithSurnameFirstUppercase() . "<br/>";
echo $person->toStringWithSurnameFirstAndFirstnameAfterComma() . "<br/>";
?>

Но я застрял с DescriptiveButVeryLongToStringMethodNames,
Я хочу просто echo $person; в коде.

Мое первое решение — разместить switch-case внутри __toString() метод. Условный оператор зависит от состояния класса, хранящегося в статической переменной self::$chosenToStringMethod, Поэтому мне нужен статический метод для установки состояния класса, а также констант класса, которые служат перечислениями.

<meta charset='utf-8'/>
<?php
class Person
{
protected $firstname;
protected $surname;

const PRINT_FIRSTNAME_FIRST = 1;
const PRINT_SURNAME_FIRST_UPPERCASE = 2;
const PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA = 3;

static private $chosenToStringMethod;

public function __construct($firstname, $surname)
{
$this->firstname = $firstname;
$this->surname = $surname;
}

static public function setToStringMethod($choice)
{
self::$chosenToStringMethod = $choice;
}

private function toStringWithFirstnameFirst()
{
return $this->firstname . " " . $this->surname;
}

private function toStringWithSurnameFirstUppercase()
{
$surnameConverted = mb_convert_case($this->surname, MB_CASE_UPPER, "UTF-8");
return $surnameConverted . " " . $this->firstname;
}

private function toStringWithSurnameFirstAndFirstnameAfterComma()
{
return $this->surname . ", " . $this->firstname;
}

public function __toString()
{
switch (self::$chosenToStringMethod) {
case self::PRINT_FIRSTNAME_FIRST:
return $this->toStringWithFirstnameFirst();
break;
case self::PRINT_SURNAME_FIRST_UPPERCASE:
return $this->toStringWithSurnameFirstUppercase();
break;
case self::PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA:
return $this->toStringWithSurnameFirstAndFirstnameAfterComma();
break;
default:
return "No __toString method set";
break;
}
}
}

$person = new Person("Thomas", "Müller");
echo $person . "<br/>";
Person::setToStringMethod(Person::PRINT_FIRSTNAME_FIRST);
echo $person . "<br/>";
Person::setToStringMethod(Person::PRINT_SURNAME_FIRST_UPPERCASE);
echo $person . "<br/>";
Person::setToStringMethod(Person::PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA);
echo $person . "<br/>";
?>

Я вижу некоторые недостатки этого решения:

  • Person класс становится тяжелым
  • switch-case заявления могут скрыть некоторые ошибки

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

1

Решение

Хорошо, я предполагаю, что причина, по которой вы спрашиваете, состоит в том, что вы хотите сохранить вещи в чистоте, но нет способа установить метод __toString () для существующего объекта, поэтому лучшим решением будет разделение функциональности.

Сначала создайте PersonRender:

class PersonRender
{
const PRINT_FIRSTNAME_FIRST = 1;
const PRINT_SURNAME_FIRST_UPPERCASE = 2;
const PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA = 3;

static public $chosenToStringMethod;

private $person;

public function __construct($person)
{
$this->person = $person;
}

public function render()
{
switch (self::$chosenToStringMethod)
{
case self::PRINT_SURNAME_FIRST_UPPERCASE :
return $this->toStringWithSurnameFirstUppercase();
case self::PRINT_SURNAME_FIRST_FIRSTNAME_AFTER_COMMA :
return $this->toStringWithSurnameFirstAndFirstnameAfterComma();
default :
return $this->toStringWithFirstnameFirst();
}
}

private function toStringWithFirstnameFirst()
{
return "{$this->person->firstname} {$this->person->surname}";
}

private function toStringWithSurnameFirstUppercase()
{
$surnameConverted = mb_convert_case($this->person->surname, MB_CASE_UPPER, "UTF-8");
return "{$surnameConverted} {$this->person->firstname}";
}

private function toStringWithSurnameFirstAndFirstnameAfterComma()
{
return "{$this->person->surname}, {$this->person->firstname}";
}

}

а затем класс Person:

class Person
{

public $firstname, $surname;

public function __construct($firstname, $surname)
{
$this->firstname = $firstname;
$this->surname = $surname;
}

public function __toString() {
$render = new PersonRender($this);
return $render->render();
}
}

и небольшой тест:

$person = new Person('Foo', 'Bar');
echo $person;
echo '<hr />';
PersonRender::$chosenToStringMethod = PersonRender::PRINT_SURNAME_FIRST_UPPERCASE;
echo $person;

РЕДАКТИРОВАТЬ 1
чтобы сохранить код в чистоте, класс сущности Person должен, конечно, иметь приватные реквизиты, имя и верное имя, а также устанавливать и получать методы

2

Другие решения

На мой взгляд, самый простой способ — просто указать получатель для имени и фамилии и вручную собрать строки, где они вам нужны. В ваших текущих решениях вы просто загрязняете свое рабочее пространство ненужными классами и делаете класс Person сложнее, чем должно быть.

0

По вопросам рекламы [email protected]