【问题标题】:PHP: add a custom method to a(n internal) class (derived from exception class) at runtimePHP:在运行时向(n个内部)类(从异常类派生)添加自定义方法
【发布时间】:2014-12-16 12:52:17
【问题描述】:

我扩展了异常类以添加方法 getMessageHTML()。 在我的应用程序中,我想捕获任何异常 - 以及派生内部类的异常,例如ReflectionException - 并且希望能够对任何异常和任何派生异常使用 getMessageHTML() 方法或其他自定义方法。

有什么方法可以在运行时向内部类(如异常类或 ReflectionException 类)添加方法或特征?

我想到的唯一解决方案是将任何捕获的异常包装到我的扩展异常类中,例如:

$anyException = new Exception(); //or ReflectionException, or ...
$wrappedException = MyException::wrap($anyException);
$wrappedException->getMessageHTML(); //or any other custom method

是否有任何实现,允许向每个派生的内部或外部类/对象引入方法,以便任何对象都知道它?

$anyException = new Exception(); //or ReflectionException, or ...
$anyException->getMessageHTML();

那么我可以简单地做:

try
{
    throw <anyException>(); //like throw Exception() or throw ReflectionException() ...
}
catch($e)
{
    $e->getMessageHTML(); //its assured that the method is known.
}

【问题讨论】:

  • PHP 类是密封的并且支持猴子补丁is quite poor。所以恐怕答案是“不可能”。
  • getMessageHtml() 的实现是什么样的?是不是不可能创建一个以异常为参数的 ExceptionView 并在您的视图中发生转换为 HTML 的逻辑?
  • 感谢您到目前为止的回复。视图的想法类似于使用包装器方法的想法 - 在这种情况下,包装器方法执行视图。

标签: php methods runtime add


【解决方案1】:

现在我是这样做的:

class MyException extends Exception
{
    protected static function cast($destination, $sourceObject)
    {
        if(is_string($destination))
            $destination = new $destination();

        $sourceReflection = new \ReflectionObject($sourceObject);
        $destinationReflection = new \ReflectionObject($destination);
        $sourceProperties = $sourceReflection->getProperties();

        foreach($sourceProperties as $sourceProperty)
        {
            $sourceProperty->setAccessible(true);
            $name = $sourceProperty->getName();
            $value = $sourceProperty->getValue($sourceObject);
            if ($destinationReflection->hasProperty($name))
            {
                $propDest = $destinationReflection->getProperty($name);
                $propDest->setAccessible(true);
                $propDest->setValue($destination,$value);
            }
            else
                $destination->$name = $value;
        }
        return $destination;
    }

    public static function wrap(Exception $exception)
    {
        $wrap = $exception;
        if(!$exception instanceof MyException)
            $wrap = self::cast(__CLASS__, $exception);
        return $wrap;
    }

    public function getMessageHTML()
    {
        //some code ...
    }

}

try
{
    throw new ReflectionException('test');
}
catch(Exception $e)
{
    $e = MyException::wrap($e);
    echo $e->getMessageHTML();
}

【讨论】:

    【解决方案2】:

    或者 - 更简单 - 并且具有前面的异常可用的优势:

    class MyException extends Exception
    {
        public static function wrap(Exception $exception)
        {
            $wrap = $exception;
            if(!$exception instanceof AppException)
            {
                try
                {
                    throw new AppException($exception->getMessage(), $exception->getCode(), $exception);
                }
                catch(AppException $e)
                {
                    $wrap = $e;
                }
            }
            return $wrap;
        }
    
        public function getMessageHTML()
        {
            //some code ...
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-14
      • 2021-09-09
      • 2012-06-23
      • 2021-12-23
      • 2021-06-17
      • 2017-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多