21

I have derived a class from Exception, basically like so:

class MyException extends Exception {

    private $_type;

    public function type() {
        return $this->_type; //line 74
    }

    public function __toString() {

        include "sometemplate.php";
        return "";

    }

}

Then, I derived from MyException like so:

class SpecialException extends MyException {

    private $_type = "superspecial";

}

If I throw new SpecialException("bla") from a function, catch it, and go echo $e, then the __toString function should load a template, display that, and then not actually return anything to echo.

This is basically what's in the template file

<div class="<?php echo $this->type(); ?>class">

    <p> <?php echo $this->message; ?> </p>

</div>

in my mind, this should definitely work. However, I get the following error when an exception is thrown and I try to display it:

Fatal error: Cannot access private property SpecialException::$_type in C:\path\to\exceptions.php on line 74

Can anyone explain why I am breaking the rules here? Am I doing something horribly witty with this code? Is there a much more idiomatic way to handle this situation? The point of the $_type variable is (as shown) that I want a different div class to be used depending on the type of exception caught.

tuergeist
  • 9,171
  • 3
  • 37
  • 58
Carson Myers
  • 37,678
  • 39
  • 126
  • 176
  • As I wrote down there: It is very very very ugly to let __toString() return an empty string. I really can't see ANY usecase for such stuff. – tuergeist Nov 19 '09 at 10:29
  • The empty return of __toString() for an Exception is even more doubtful. – tuergeist Nov 19 '09 at 10:31

8 Answers8

44

just an example how to access private property

<?php
class foo {
    private $bar = 'secret';
}
$obj = new foo;


if (version_compare(PHP_VERSION, '5.3.0') >= 0)
{

      $myClassReflection = new ReflectionClass(get_class($obj));
      $secret = $myClassReflection->getProperty('bar');
      $secret->setAccessible(true);
      echo $secret->getValue($obj);
}
else 
{
    $propname="\0foo\0bar";
    $a = (array) $obj;
    echo $a[$propname];
}
Fivell
  • 11,829
  • 3
  • 61
  • 99
41

Name the variable protected:

* Public: anyone either inside the class or outside can access them
* Private: only the specified class can access them. Even subclasses will be denied access.
* Protected: only the specified class and subclasses can access them
dfilkovi
  • 3,051
  • 7
  • 39
  • 51
  • 2
    Note: In PHP `protected` means that your parents can access them, too. – soulmerge Nov 19 '09 at 10:03
  • alright, I did this -- but now I can't use `$this->message` -- no error, it just displays nothing... why? – Carson Myers Nov 19 '09 at 10:10
  • nevermind, I was setting `$message` in the parent constructor instead of `$this->message`. Also, I realized I provided no actual implementation details of how I was setting the message in the first place. My bad – Carson Myers Nov 19 '09 at 10:15
13

See my answer here: https://stackoverflow.com/a/40441769/1889685


As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.

The Closure class

For example we have a class with a private variable and we want to access it outside the class:

class Foo {
    private $bar = "Foo::Bar";
}

PHP 5.4+

$foo = new Foo;
$getFooBarCallback = function() {
    return $this->bar;
};

$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar

As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:

PHP 7+

$foo = new Foo;
$getFooBar = function() {
    return $this->bar;
};

echo $getFooBar->call($foo); // Prints Foo::Bar
Will B.
  • 17,883
  • 4
  • 67
  • 69
Christos Lytras
  • 36,310
  • 4
  • 80
  • 113
0

You need to set the access to protected. Private means that it can only be accessed from within it's own class and can't be inherited. Protected allows it to be inhherited but it still can't be accessed directly from outside the class.

RMcLeod
  • 2,561
  • 1
  • 22
  • 38
0

If you check the visibility documentation, buried in a comment is:

// We can redeclare the public and protected method, but not private

You should make it protected to do what you're trying to do.

Incidentally, it looks like you're just setting it to be the class name - you could just use get_class():

<div class="<?php echo get_class($this); ?>class">
Greg
  • 316,276
  • 54
  • 369
  • 333
  • sure, but then if I changed the (php) class name I'd have to change the (css) class name, and also, if I want to use more information in the exception template file, I would probably add it the same way I added the "type" property. – Carson Myers Nov 19 '09 at 10:08
0

You should indeed change the accessmodifier to protected when you'e builing inheritance classes.

One extra point though; don't use return ""; but just use return;

Ben Fransen
  • 10,884
  • 18
  • 76
  • 129
  • your extra point causes a fatal error, I tried that already -- `__toString()` **MUST** return a string – Carson Myers Nov 19 '09 at 10:09
  • Ah I'm sorry! I looked over your __toString function.. just saw you were returning 'nothing'. You're absolutely right! – Ben Fransen Nov 19 '09 at 10:24
  • It is very very very ugly to let __toString() return an empty string. I really can't see ANY usecase for such stuff. But you're right, __toString() must return a string. – tuergeist Nov 19 '09 at 10:28
0

Cannot access $this outside of a class. Instead, need to call an instance of the class. Then, access a function within the class which will return the message.

  • 2
    Well, a programmer would give a code snippet to clear things up. Right? [Here's](https://stackoverflow.com/help/how-to-answer) a guide. Thank you. –  Feb 28 '20 at 00:53
0

There is this way by using \Closure :

$reader = function ($object, $property) {
    $value = \Closure::bind(function () use ($property) {
         return $this->$property;
    }, $object, $object)->__invoke();

    return $value;
};

$myClass = new MyClass();
$property = $reader($myClass, 'yourProperty');
echo $property; // will display the value of property
Astro-Otter
  • 736
  • 1
  • 10
  • 22