I have a class that handles errors with exceptions, like
class fooException extends Exception{}
class foo {
public function bar($x){
if(!$x){
throw new fooException ("x can not be false value");
}
}
}
Now, what I am trying to do, is allow user of the class to make choices whether an exception should be thrown, or not just like the PDO class.
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
So, I was to give flexibility to the class not to throw exceptions all the time.
You could extend the Exception in a better way
class MyException extends Exception
{
static public $enable = true;
public function __construct($message = null, $code = 0)
{
if (self::$enable) {
parent::__construct($message, $code);
}
}
}
the you could call
throw new MyException("x can not be false value");
MyException::enable = false; //for disable
Note this is really very basic implementation and you have the problem to handle the false state in some way.
Another better solution is to use an ExceptionHandler
class ExceptionHanlder
{
static public $enable = true;
function __construct($message = null,$code = null) {
if (self::$enable) {
throw new Exception($message,$code);
}
}
}
ExceptionHandler::$enable = false;
new ExceptionHandler('test');
Related
I extended the exception class amongst other things to add a method getMessageHTML().
In my application I want to catch any exception - also exceptions of derived internal classes like e.g. the ReflectionException - and want to be able to use a getMessageHTML() method or other custom methods on any exception and any derived exception.
Is there any way, to add a method or trait to an internal class like the exception class or the ReflectionException class at runtime?
The only solution that comes to my mind is to wrap any catched exception into my extended exception class like:
$anyException = new Exception(); //or ReflectionException, or ...
$wrappedException = MyException::wrap($anyException);
$wrappedException->getMessageHTML(); //or any other custom method
is there any implementation, that allows to introduce a method to every derived internal or foreign class/object, so that any object knows it?
$anyException = new Exception(); //or ReflectionException, or ...
$anyException->getMessageHTML();
then i could simply do:
try
{
throw <anyException>(); //like throw Exception() or throw ReflectionException() ...
}
catch($e)
{
$e->getMessageHTML(); //its assured that the method is known.
}
For now I am doing it like this:
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();
}
or - simpler - and with the advantage to have the previous exception available:
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 ...
}
}
I basically need to call one of two constructors from my PHP class dependent on wheter or not verification is needed.
My current code looks like this:
class Event extends Generic {
private $user_id;
function __construct($user_id=null) {
$this->user_id = $user_id;
}
public function verify($user_id=null, $identifier=null) {
if (parent::verifyUser($user_id, $identifier)) {
return new Event($user_id);
}
else {
// what gets retruend here in the event of a failure???
}
}
public function noverify($user_id=null) {
return new Event(user_id);
}
}
Calling the code like so:
$event = new Event();
$obj1 = $event->noverify(5);
$obj2 = $event->verify(5, 100);
I'm really not clear how I should handle the event of a failed constructor if the condition inside fails. Am I heading down the wrong path here?
I would either throw an Exception or return FALSE:
else {
throw new Exception('verification failed');
}
or
else {
return FALSE;
}
PHP calls private method in parent class instead of method define in current class called by call_user_func
class Car {
public function run() {
return call_user_func(array('Toyota','getName')); // should call toyota
}
private static function getName() {
return 'Car';
}
}
class Toyota extends Car {
public static function getName() {
return 'Toyota';
}
}
$car = new Car();
echo $car->run(); //Car instead of Toyota
$toyota = new Toyota();
echo $toyota->run(); //Car instead of Toyota
I have found a solution with a different approach..
<?php
class Car {
public static function run() {
return static::getName();
}
private static function getName() {
return 'Car';
}
}
class Toyota extends Car {
public static function getName() {
return 'Toyota';
}
}
echo Car::run();
echo Toyota::run();
?>
Using Late Static Binding..
You might use something like this:
<?php
class Car {
public function run() {
return static::getName();
}
private static function getName(){
return 'Car';
}
}
class Toyota extends Car {
public static function getName(){
return 'Toyota';
}
}
$car = new Car();
echo $car->run();
echo PHP_EOL;
$toyota = new Toyota();
echo $toyota->run();
?>
Output:
Car
Toyota
PHP 5.4.5
This is a bug that appears to have fluctuated in and out of existence for a long time (see #deceze's tests in comments on the question). It is possible to "fix" this issue - that is, give consistent behaviour across PHP versions - using reflection:
Works in PHP 5.3.2 and later due to a dependency on ReflectionMethod::setAccessible() to invoke private/protected methods. I will add further explanation for this code, what it can and can't do and how it works very shortly.
Unfortunately it's not possible to test this directly on 3v4l.org because the code is too large, however this is the first ever real use case for minifying PHP code - it does work on 3v4l if you do this, so feel free to play around and see if you can break it. The only issue I'm aware of is that it doesn't currently understand parent. It is also restricted by the lack of $this support in closures before 5.4, there's not really anything that can be done about this though.
<?php
function call_user_func_fixed()
{
$args = func_get_args();
$callable = array_shift($args);
return call_user_func_array_fixed($callable, $args);
}
function call_user_func_array_fixed($callable, $args)
{
$isStaticMethod = false;
$expr = '/^([a-z_\x7f-\xff][\w\x7f-\xff]*)::([a-z_\x7f-\xff][\w\x7f-\xff]*)$/i';
// Extract the callable normalized to an array if it looks like a method call
if (is_string($callable) && preg_match($expr, $callable, $matches)) {
$func = array($matches[1], $matches[2]);
} else if (is_array($callable)
&& count($callable) === 2
&& isset($callable[0], $callable[1])
&& (is_string($callable[0]) || is_object($callable[0]))
&& is_string($callable[1])) {
$func = $callable;
}
// If we're not interested in it use the regular mechanism
if (!isset($func)) {
return call_user_func_array($func, $args);
}
$backtrace = debug_backtrace(); // passing args here is fraught with complications for backwards compat :-(
if ($backtrace[1]['function'] === 'call_user_func_fixed') {
$called = 'call_user_func_fixed';
$contextKey = 2;
} else {
$called = 'call_user_func_array_fixed';
$contextKey = 1;
}
try {
// Get a reference to the target static method if possible
switch (true) {
case $func[0] === 'self':
case $func[0] === 'static':
if (!isset($backtrace[$contextKey]['object'])) {
throw new Exception('Use of self:: in an invalid context');
}
$contextClass = new ReflectionClass($backtrace[$contextKey][$func[0] === 'self' ? 'class' : 'object']);
$contextClassName = $contextClass->getName();
$method = $contextClass->getMethod($func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if (!$method->isStatic()) {
throw new Exception('Attempting to call instance method in a static context');
}
$invokeContext = null;
if ($method->isPrivate()) {
if ($ownerClassName !== $contextClassName
|| !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
if (!method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method in an invalid context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
break;
case is_object($func[0]):
$contextClass = new ReflectionClass($func[0]);
$contextClassName = $contextClass->getName();
$method = $contextClass->getMethod($func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if ($method->isStatic()) {
$invokeContext = null;
if ($method->isPrivate()) {
if ($ownerClassName !== $contextClassName || !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
if (!method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method in an invalid context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
} else {
$invokeContext = $func[0];
}
break;
default:
$contextClass = new ReflectionClass($backtrace[$contextKey]['object']);
$method = new ReflectionMethod($func[0], $func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if (!$method->isStatic()) {
throw new Exception('Attempting to call instance method in a static context');
}
$invokeContext = null;
if ($method->isPrivate()) {
if (empty($backtrace[$contextKey]['object'])
|| $func[0] !== $contextClass->getName()
|| !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
$contextClass = new ReflectionClass($backtrace[$contextKey]['object']);
if (empty($backtrace[$contextKey]['object']) || !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method outside a class context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
break;
}
// Invoke the method with the passed arguments and return the result
return $method->invokeArgs($invokeContext, $args);
} catch (Exception $e) {
trigger_error($called . '() expects parameter 1 to be a valid callback: ' . $e->getMessage(), E_USER_ERROR);
return null;
}
}
Use "protected" modifier if you want to get access from parent and descendants only. IMO, it's obvious. For example:
<?php
class Car {
public function run() {
return call_user_func(array('static','getName'));
}
protected static function getName() {
return 'Car';
}
}
class Toyota extends Car {
protected static function getName() {
return 'Toyota';
}
}
$car = new Car();
echo $car->run(); // "Car"
$toyota = new Toyota();
echo $toyota->run(); // "Toyota"
You can use get_called_class() instead of 'static'.
The problem is, I think, with the different access levels of the two getname functions. If you make the base class version of getname() public (the same as the derived class version), then in php 5.3.15 (on my Mac), you get Toyota. I think that, because of the different access levels, you end up with two different versions of the getname() function in the Toyota class, rather than the derived class version overriding the base class version. In other words, you have overloading rather than overriding. Therefore, when the run() function looks for a getname() function in the Toyota class to execute, it finds two and takes the first one, which would be the first to be declared (from the base class).
Granted this is just supposition on my part, but it sounds plausible.
use the get_called_called function todo this
public function run() {
$self = get_called_class();
return $self::getName();
}
I believe you're functions are overriding each other and by default going to the first one. Unless you change the parameters of one function, or rename the function it will always default to the parent class function.
I would like to typecast PHP exceptions. Consider the following code:
class myException extends Exception {
function __construct( $mOrigin = "", $iCode = 0, Exception $oPrevious = null){
if(is_string($mOrigin)){
parent::__construct($mOrigin, $iCode, $oPrevious);
} elseif ($mOrigin instanceof Exception) {
parent::__construct($mOrigin->getMessage(),$mOrigin->getCode(),$mOrigin->getPrevious());
$this->file = $mOrigin->getFile();
$this->line = $mOrigin->getLine();
} else {
parent::__construct("\$mOrigin has wrong type", self::eFatal, $oPrevious);
}
}
The idea is to turn a standard Exception into a myException preserving the original stack trace. Since the variables holding the trace are private I cannot copy these values immediately and the CTOR produces a new one for myException.
The first idea was of course to use clone, but I can hardly re-assign $this, can I?
So what I'm trying to do is a C++ style typecast CTOR. Is there a sensible paradigm in PHP to do this?
Why not just set trace & previous the same way as file & line?
class myException extends Exception {
function __construct( $mOrigin = "", $iCode = 0, Exception $oPrevious = null){
if(is_string($mOrigin)){
parent::__construct($mOrigin, $iCode, $oPrevious);
} elseif ($mOrigin instanceof Exception) {
parent::__construct($mOrigin->getMessage(),$mOrigin->getCode(),$mOrigin->getPrevious());
$this->file = $mOrigin->getFile();
$this->line = $mOrigin->getLine();
$this->trace = $mOrigin->getTrace();
$this->previous = $mOrigin->getPrevious();
} else {
parent::__construct("\$mOrigin has wrong type", self::eFatal, $oPrevious);
}
}
EDIT:
See comments below regarding why I got away w/ this code earlier.
Why not turn your myException class into a decorator:
class myException extends Exception {
private $_oException;
function __construct( $mOrigin = "", $iCode = 0, Exception $oPrevious = null){
if(is_string($mOrigin)){
parent::__construct($mOrigin, $iCode, $oPrevious);
} elseif ($mOrigin instanceof Exception) {
$this->_oException = $mOrigin;
parent::__construct($mOrigin->getMessage(),$mOrigin->getCode(),$mOrigin->getPrevious());
$this->file = $mOrigin->getFile();
$this->line = $mOrigin->getLine();
} else {
parent::__construct("\$mOrigin has wrong type", self::eFatal, $oPrevious);
}
}
function getTrace()
{
return $this->_oException->getTrace();
}
function getPrevious()
{
return $this->_oException->getPrevious();
}
}
FUTHER INFO:
I've followed up on php-general and it turns out this is the intended behavior and it works the same in Java et al as well. You can override the member variable in child classes and have a separate store with the same name. This compiles just fine in java
public class PrivateAccess
{
private Boolean isAccessible = true;
public Boolean getAccessible()
{
return isAccessible;
}
}
class PrivateAccessChild extends PrivateAccess
{
private Boolean isAccessible = false;
public Boolean getAccessible()
{
return isAccessible;
}
public Boolean getParentAccessible()
{
return super.getAccessible();
}
public static void main(String[] args)
{
PrivateAccessChild pAccess = new PrivateAccessChild();
if(!pAccess.getAccessible())
System.out.println("we're hitting the child here...");
if(pAccess.getParentAccessible())
System.out.println("we're hitting the parent here...");
System.out.println("we're done here...");
}
}
In a lot of my PHP classes, I have this code:
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
The point is so that outside code can know if an object has an error state, what the string of the error is, etc. But to have this exact code in a bunch of different classes is repetitious!
I'd love to have a dual-extension where I could do
class childClass extends parentClass, error {
...
}
And have those properties and methods inborn, But PHP doesn't support multiple inheritances. What I'm thinking about doing is creating an error class that exists inside each class. If I make it public, I can call it directly through the object
if ( $myObject->error->isError() ) {...}
but wouldn't that also make its error status settable from outside the containing class,
$myObject->error->setError("I shouldn't be doing this here");
which I would rather avoid?
Or I could write 'gateway' functions in the containing class, which do the appropriate calls on the error object, and prevent setting the error status from outside,
class childClass extends parentClass {
private $error;
public function __construct(...) {
...
$error = & new error();
...
}
public function isError() {...}
public function getError() {...}
public function getErrorCode() {...}
private function setError() {...}
...
}
but that leads to (some of) the code duplication that I'm trying to avoid.
What's the optimal solution here? I'm trying to have functionality for error statuses for a number of objects, so that the outside world can see their error state, with minimal repetition.
Use composition instead of inheritance.
class Errors {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
And now use a private instance variable to refer to it:
class childClass extends parentClass {
private $errors = new Errors();
...
}
The private visibility prevents you from referencing $errors outside of the class.
There's also no need to create isError(), getError(), etc. inside childClass (and therefore no need to worry about code duplication). Simply call $this->errors->isError(), $this->errors->getError(), etc. If you still wanted to require those methods to be implemented though, as suggested below, you could specify an interface.
You could also abuse the __call magic method to do the same thing:
public function __call($name, array $arguments) {
$name = strtolower($name);
if (isset($this->methods[$name])) {
array_unshift($arguments, $this);
return call_user_func_array($this->methods[$name], $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
Note that I said abuse... Ideally, I'd think of a different architecture rather than having all these "common methods" everywhere. Why not use an exception instead of checking $foo->isError? If that's not appropriate, why not decorate a class?
class Errors
protected $object = null;
public function __construct($object) {
$this->object = $object;
}
public function __call($method, array $arguments) {
$callback = array($this->object, $method);
if (is_callable($callback)) {
return call_user_func_array($callback, $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
public function __get($name) { return $this->object->$name; }
public function __set($name, $value) { $this->object->$name = $value; }
// Your methods here
public function isInstance($name) { return $this->object instanceof $name; }
}
Then just "wrap" your existing object in that class:
$obj = new Errors($obj);
$obj->foo();
As of PHP 5.4, you can use Traits.
For example you could make Trait called ErrorTrait like this:
trait ErrorTrait {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
Then you would define your child class like this:
class childClass extends parentClass {
use ErrorTrait;
...
}
Traits work basically like copy/paste so all of the code in the trait would be available within the class (without the code duplication).