Как я могу условно заставить класс использовать черту, если она существует?

Я хочу быть в состоянии use черта если это доступно.

Очевидно, я не могу определить это внутри самого класса (синтаксическая ошибка)

//fails
include_once('myTrait.php');

class foo
{
var $bar;

if (trait_exists('myTrait')) {
use myTrait;
}
}

//also fails
foo use myTrait;

//also fails
$f = new foo();
$f use myTrait;

//also fails
$f = new foo() use myTrait;

В идеальном случае сценарий будет примерно таким:

class foo
{
var $bar;
}

if (file_exists('myTrait.php')) {
include_once('myTrait.php');
//make class foo use myTrait;
}

$f=new foo();

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

Подсказки, документация и объяснения приветствуются как обычно.


Самый близкий мой поиск привел меня в этой статье http://brendan-bates.com/traits-the-right-way/

Скажем, некоторые из этих контроллеров (но не все) требуют
подключение к базе данных. Чтобы сохранить производительность, мы не должны давать каждому
Контроллер подключения к базе данных. Что мы могли бы сделать, это написать
абстрактный класс, который расширяет BaseController, который предоставляет базу данных
подключение. Но в будущем, что если объект, который не является
контроллер требует подключения к базе данных? Вместо того, чтобы дублировать это
Логика, мы можем использовать горизонтальное повторное использование.

Простая черта может быть создана:

trait DatabaseAware
{
protected $db;

public function setDatabase($db)
{
$this->db = $db;
}

protected function query($query)
{
$this->db->query($query);
}
}

Эта черта теперь обеспечивает классы с общей функциональностью базы данных.
Любой класс, который требует подключения к базе данных, будь то контроллер или
менеджер (или что-то еще) может использовать эту черту:

class IndexController extends BaseController
{
use DatabaseAware;

public function indexAction()
{
$this->query("SELECT * FROM `someTable`");
}
}

Где, как я реализую черты в зависимости от потребностей моих различных объектов. Подключение к базе данных, отладка отчетов и т. Д.

2

Решение

Ваш вопрос забавный, и eval (), вероятно, соответствует вашим потребностям. Этот стиль, использующий генерацию кода, уродлив, но я знаю, что он работает, потому что я сам проверил его на своей машине. Вот как вы можете это сделать:

$src = '
class foo {
var $bar; // and all of your other code goes here
';
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
$src .= "use myTrait;\n";
}
$src .= "}";
eval ($src); // your class finally gets declared

Я не часто использую eval (), но это забавно, когда он решает проблему, которая иначе не может быть традиционно решена.

0

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

Легко!

Черта характера

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

<?php

trait BarTrait
{
public function bar()
{
return 'Hey, I am your friend!';
}
}

Интерфейс

Интерфейс, который мы ищем для реализации:

<?php

interface BarInterface
{
/**
* @return string
*/
public function bar();
}

Класс, использующий черту

Класс FooUsingBarTrait который использует черту BarTrait Для реализации вышеупомянутого интерфейса:

<?php

class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}

Класс не использует черту

Класс FooNotUsingBarTrait который не использует черту BarTrait, но вместо этого реализует сам вышеупомянутый интерфейс:

class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}

Условно создайте определение класса

Наконец, условно определить класс Fooв зависимости от того, является ли черта BarTrait существует или нет:

<?php

if (trait_exists(BarTrait::class) {
class Foo extends FooUsingBarTrait
{
}
} else {
class Foo extends FooNotUsingBarTrait
{
}
}

Создайте свой экземпляр

$foo = new Foo();

$foo->bar();

var_dump(
get_class($foo),
class_parents(Foo::class)
);

Заметка Это, вероятно, имеет смысл, если оба класса FooUsingBarTrait а также FooNotUsingBarTrait реализовать общий интерфейс — в конце концов, вы, вероятно, захотите предоставить некоторую функциональность, которая будет разделена между двумя реализациями: одна использует черту, другая другими средствами (методы, предоставляемые этим классом).

Для справки смотрите:

Например, смотрите:

4

Вот чем я закончил:

eval("class myClass {". (trait_exists('myTrait') ? "use myTrait;" : "")
. str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);

Полная лень:

  • дублировать trait_exists линия, чтобы добавить больше черт
  • Комментарии из class Ключевое слово и <?php тег, так что вам не нужно редактировать файл класса
  • оценивает одну длинную строку вонючего кода.

Это работает просто отлично для меня и «как есть» без каких-либо изменений в каком-либо файле, кроме того, в который я вставляю эту строку. Это, вероятно, не будет иметь место для вас.

Учтите тот факт, что:

  • не используйте закрывающий тег php
  • только один класс по файлу
  • Вам нужно добавить любые другие ключевые слова (расширяет, реализует, …)
  • и, возможно, более неожиданное поведение в зависимости от вашего кода

Спасибо lacalheinz за его поучительный пост, но Стивен нацелился на буллиты с помощью eval ().

-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector