Волшебный метод PHP __ обращается к подклассам

Начальная загрузка моего компьютера этим утром, я столкнулся с точной проблемой для проекта, я продолжаю работать. У меня были некоторые идеи, которые приводят к следующему дизайну - и комментарии были бы более, чем потрясающими. К сожалению, дизайн, предложенный Josh, не возможен, поскольку я должен работать с удаленным SQL-сервером и не могу включить Распределять Координатору Транзакции сервис, на который он полагается.

Мое решение основано на нескольких все же простых изменениях в моем существующем коде.

Первый, у меня есть вся своя реализация репозиториев простой интерфейс маркера:

/// <summary>
/// A base interface for all repositories to implement.
/// </summary>
public interface IRepository
{ }

, Во-вторых, я позволяю включенным репозиториям всей своей транзакции, реализуют следующий интерфейс:

/// <summary>
/// Provides methods to enable transaction support.
/// </summary>
public interface IHasTransactions : IRepository
{
    /// <summary>
    /// Initiates a transaction scope.
    /// </summary>
    void BeginTransaction();

    /// <summary>
    /// Executes the transaction.
    /// </summary>
    void CommitTransaction();
}

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

#region IHasTransactions Members

public void BeginTransaction()
{
    _db.Transaction = _db.Connection.BeginTransaction();
}

public void CommitTransaction()
{
    _db.Transaction.Commit();
}

#endregion

Это, конечно, требует, чтобы новый класс репозитория был создан для каждого потока, но это разумно для моего проекта.

Каждый метод с помощью репозитория должен вызвать BeginTransaction() и EndTransaction(), если репозиторий реализует IHasTransactions. Для совершения этого еще легче вызова я придумал следующие расширения:

/// <summary>
/// Extensions for spawning and subsequently executing a transaction.
/// </summary>
public static class TransactionExtensions
{
    /// <summary>
    /// Begins a transaction if the repository implements <see cref="IHasTransactions"/>.
    /// </summary>
    /// <param name="repository"></param>
    public static void BeginTransaction(this IRepository repository)
    {
        var transactionSupport = repository as IHasTransactions;
        if (transactionSupport != null)
        {
            transactionSupport.BeginTransaction();
        }
    }

    public static void CommitTransaction(this IRepository repository)
    {
        var transactionSupport = repository as IHasTransactions;
        if (transactionSupport != null)
        {
            transactionSupport.CommitTransaction();
        }
    }
}

Комментарии ценятся!

9
задан nickf 8 October 2009 в 01:40
поделиться

4 ответа

__ call () вызывается только тогда, когда функция не найдена иным образом, поэтому ваш пример в том виде, в каком он написан, невозможен.

14
ответ дан 4 December 2019 в 12:19
поделиться

Это невозможно сделать напрямую, но это одна из возможных альтернатив:

class SubFoo { // does not extend
    function __construct() {
        $this->__foo = new Foo; // sub-object instead
    }
    function __call($func, $args) {
        echo "intercepted $func()!\n";
        call_user_func_array(array($this->__foo, $func), $args);
    }
}

Подобные вещи хороши для отладки и тестирования, но вы хотите избежать __ call () и друзья как можно больше в производственном коде, поскольку они не очень эффективны.

2
ответ дан 4 December 2019 в 12:19
поделиться

Если вам нужно добавить что-то дополнительное к родительской панели (), можно ли это сделать?

class SubFoo extends Foo {
    function bar() {
        // Do something else first
        parent::bar();
    }
}

или это просто вопрос из любопытства?

0
ответ дан 4 December 2019 в 12:19
поделиться

Для того, чтобы получить такой же эффект, можно сделать следующее:

    <?php

class hooked{

    public $value;

    function __construct(){
        $this->value = "your function";
    }

    // Only called when function does not exist.
    function __call($name, $arguments){

        $reroute = array(
            "rerouted" => "hooked_function"
        );

        // Set the prefix to whatever you like available in function names.
        $prefix = "_";

        // Remove the prefix and check wether the function exists.
        $function_name = substr($name, strlen($prefix));

        if(method_exists($this, $function_name)){

            // Handle prefix methods.
            call_user_func_array(array($this, $function_name), $arguments);

        }elseif(array_key_exists($name, $reroute)){

            if(method_exists($this, $reroute[$name])){

                call_user_func_array(array($this, $reroute[$name]), $arguments);

            }else{
                throw new Exception("Function <strong>{$reroute[$name]}</strong> does not exist.\n");
            }

        }else{
            throw new Exception("Function <strong>$name</strong> does not exist.\n");
        }

    }

    function hooked_function($one = "", $two = ""){

        echo "{$this->value} $one $two";

    }

}

$hooked = new hooked();

$hooked->_hooked_function("is", "hooked. ");
// Echo's: "your function is hooked."
$hooked->rerouted("is", "rerouted.");
// Echo's: "our function is rerouted."

?>
0
ответ дан 4 December 2019 в 12:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: