Preamble:
What I'm after is; if a method calls the get_typed_ancestor() method, the class name needed to perform the operations required in get_typed_ancestor() is the name of the class in which the calling method is defined.
Passing $this to extract the class name fails because it will resolve to the concrete class. If the calling method is defined in an abstract class higher up the hierarchy than the concrete class of which the instance is, we get the incorrect class name.
Looking for an instanceof static fails for the same reason as described above.
As described below, the purpose for capturing the class name in which the method is defined, is so that get_typed_ancestor() can find an instance of any class derived from the class in which the calling method is defined, not just another instance of the concrete class that initiated the call stack (hence $this and static being unsatisfactory)
So far, passing __CLASS__ to get_typed_ancestor() seems to the be the only solution thus far, as __CLASS__ will properly resolve to the class name in which the calling method is defined, not the class name of the instance invoking the calling method.
Note:
I've included at the end of this question an example showing the working __CLASS__ argument approach, and the failed static approach. If you wanna take a stab, perhaps use that as a start.
Question:
I've seen several "solutions" floating around that leverage debug_backtrace() to capture the calling class of a given method or function; these however are (as my quotation marks may suggest) not exactly solutions as far as I'm concerned, as debug_backtrace() used in this manner is a hack.
Rant aside, if this hack is the only answer, then hack I shall.
Anyways; I'm working on a set of classes that act as nodes in a bottom-to-top traversable tree. Here's a class hierarchy, simplified for brevity:
abstract class AbstractNode{}
abstract class AbstractComplexNode extends AbstractNode{}
class SimpleNode extends AbstractNode{}
class ComplexNodeOne extends AbstractComplexNode{}
class ComplexNodeTwo extends AbstractComplexNode{}
Nodes may have any concrete node (or null) as a parent. Looking at AbstractNode:
abstract class AbstractNode{
protected $_parent;
public function get_typed_ancestor(){
// here's where I'm working
}
public function get_parent(){
return $this->_parent;
}
}
The method get_typed_ancestor() is where I'm at.
From other methods in the extending classes, get_typed_ancestor() is called to find the closest _parent of the class type to which that method belongs. This is better illustrated with an example; given the previous AbstractNode definition:
abstract class AbstractComplexNode extends AbstractNode{
public function get_something(){
if(something_exists()){
return $something;
}
$node = $this->get_typed_ancestor();
if(null !== $node){
return $node->get_something();
}
}
}
The method get_typed_ancestor(), when called from the context of AbstractComplexNode::get_something(), will be looking for an object of type (or extending type) AbstractComplexNode -- in the case of this hierarchy, the possible concrete classes being ComplexNodeOne and ComplexNodeTwo.
Since AbstractComplexNode cannot be instantiated, a concrete instance such as ComplexNodeOne would be invoking get_something().
I need to highlight a point here; the search in this previous case must be for AbstractComplexNode in order to find the first instance of either ComplexNodeOne or ComplexNodeTwo. As will be explained in a moment, searching for and instanceof static will fail, as it may skip instances of sibling classes and/or their children.
The problem is, since there are situations where the calling class is abstract, and the calling method is inherited by (and thus is called from an instance of) a class such as ComplexNodeOne, searching for a parent that is an instanceofstatic doesn't work, as static is late-bound to the concrete ComplexNodeOne.
Now, I have a solution, but I don't like it:
abstract class AbstractNode{
public function get_typed_ancestor($class){
$node = $this;
while(null !== $node->_parent){
if($node->_parent instanceof $class){
return $node->_parent;
}
$node = $node->_parent;
}
return null;
}
}
abstract class AbstractComplexNode extends AbstractNode{
public function get_something(){
if(something_exists()){
return $something;
}
$node = $this->get_typed_ancestor(__CLASS__);
if(null !== $node){
return $node->get_something();
}
}
}
This appears to work, since __CLASS__ resolves to the class name of definition. Unfortunately, I tried using __CLASS__ as a default argument to get_typed_ancestor() with no success (though that was expected)
I'm considering leaving the $class argument as an optional regardless, but if it is at all possible to "implicitly" pass this data along to the method (in absence of the optional argument) that would be great.
Solutions/Failures:
Passing __CLASS__ from the calling method as an argument to get_typed_ancestor().
Works, but is not ideal as I'd like get_typed_ancestor() to resolve the calling class without being explicitly informed of it.
In the search loop, checking if($node->_parent instanceof static).
Doesn't work when the calling class inherits the calling method. It resolves to the concrete class in which the method is called, not the one in which is defined. This failure of course applies also to self and parent.
Use debug_backtrace() to capture $trace[1]['class'] and use that for the check.
Works, but is not ideal as it's a hack.
It's tricky discussing a hierarchical data structure and supporting class hierarchy without feeling like you're confusing your audience.
Example:
abstract class AbstractNode
{
protected $_id;
protected $_parent;
public function __construct($id, self $parent = null)
{
$this->_id = $id;
if(null !== $parent)
{
$this->set_parent($parent);
}
}
protected function get_typed_ancestor_by_class($class)
{
$node = $this;
while(null !== $node->_parent)
{
if($node->_parent instanceof $class)
{
return $node->_parent;
}
$node = $node->_parent;
}
return null;
}
public function get_typed_ancestor_with_static()
{
$node = $this;
while(null !== $node->_parent)
{
if($node->_parent instanceof static)
{
return $node->_parent;
}
$node = $node->_parent;
}
return null;
}
public function set_parent(self $parent)
{
$this->_parent = $parent;
}
}
class SimpleNode extends AbstractNode
{
}
abstract class AbstractComplexNode extends AbstractNode
{
public function test_method_class()
{
var_dump($this->get_typed_ancestor_by_class(__CLASS__));
}
public function test_method_static()
{
var_dump($this->get_typed_ancestor_with_static());
}
}
class ComplexNodeOne extends AbstractComplexNode
{
}
class ComplexNodeTwo extends AbstractComplexNode
{
}
$node_1 = new SimpleNode(1);
$node_2 = new ComplexNodeTwo(2, $node_1);
$node_3 = new SimpleNode(3, $node_2);
$node_4 = new ComplexNodeOne(4, $node_3);
$node_5 = new SimpleNode(5, $node_4);
$node_6 = new ComplexNodeTwo(6, $node_5);
// this call incorrectly finds ComplexNodeTwo ($node_2), skipping
// the instance of ComplexNodeOne ($node_4)
$node_6->test_method_static();
// object(ComplexNodeTwo)#2 (2) {
// ["_id":protected]=>
// int(2)
// ["_parent":protected]=>
// object(SimpleNode)#1 (2) {
// ["_id":protected]=>
// int(1)
// ["_parent":protected]=>
// NULL
// }
// }
// this call correctly finds ComplexNodeOne ($node_4) since it's
// looking for an instance of AbstractComplexNode, resolved from
// the passed __CLASS__
$node_6->test_method_class();
// object(ComplexNodeOne)#4 (2) {
// ["_id":protected]=>
// int(4)
// ["_parent":protected]=>
// object(SimpleNode)#3 (2) {
// ["_id":protected]=>
// int(3)
// ["_parent":protected]=>
// object(ComplexNodeTwo)#2 (2) {
// ["_id":protected]=>
// int(2)
// ["_parent":protected]=>
// object(SimpleNode)#1 (2) {
// ["_id":protected]=>
// int(1)
// ["_parent":protected]=>
// NULL
// }
// }
// }
// }
For solving the problem "to capture the calling class of a given method or function", simply pass the object that creates the instance in the constructor.
<?php
class A {
public function caller() {
$b = new B ($this);
$b->bar();
}
}
class B {
$whoClass = '';
public function __construct($who)
{
$this->whoClass = get_class($who);
}
public function bar($who) {
echo get_class($this->whoClass);
}
}
Related
class SomeObject {
protected $foo,
$bar;
protected $context;
public function __construct($context) {
$this->context = $context;
}
public function setFoo($val) {
if ($this->context == 'public') {
throw new \Exception('It is impossible to modify foo property in public context!');
}
$this->foo = $val;
}
public function setBar($val) {
if ($this->context == 'api') {
throw new \Exception('It is impossible to modify bar property in API context!');
}
$this->bar = $val;
}
}
As you can see from this piece of "code" - object restricts setters depending on context value. This code is really hard to maintain. How can we rewrite it to make it beautiful and easy maintainable?
My thoughts are:
Make $context an object(s) implementing interface
isAllowed($object, $propertyName).
After making $context an object we have to thing about how can we store "restrictions" in $context object taking in mind there are a lot of different objects similar to SomeObject.
In every setter I should check $this->context->isAllowed($this, 'foo') - it looks not good. So, probably we want to add some "proxy" over SomeObject?
Passing $context to constructor also seems rather ugly for me.
What's your ideas about it?
Just two general observations:
You may want to segregate your classes into two parts: an immutable base class and a mutable extension:
class Foo {
protected $bar, $baz;
}
class MutableFoo extends Foo {
public function setBar($bar) {
$this->bar = $bar;
}
..
}
This easily solves the problem when the context is defined at object instantiation time and won't ever change. Instead of instantiating with a different context which determines the mutability, you simply instantiate a mutable or immutable version of the class.
If you still need more runtime checks, maybe simply using assertions is the best way to simplify the code:
public function setBar($bar) {
$this->assertCanSet('bar');
$this->bar = $bar;
}
protected function assertCanSet($property) {
if (!/* can set $property */) {
throw new Exception("Cannot set property $property");
}
}
Maybe on the construct, fill a list of restricted methods.
so, for instance :
class SomeObject {
protected $foo,
$bar;
protected $context;
protected $restrictedMethods;
public function __construct($context) {
$this->context = $context;
if($this->context == 'public') {
$this->restrictedMethods['setFoo'] = true;
} else if ($this->context == 'api') {
$this->restrictedMethods['setBar'] = true;
}
}
public function setFoo($val) {
if ($this->isRestricted('setFoo')) {
throw new \Exception('It is impossible to modify foo property in '.$this->context.' context!');
}
$this->foo = $val;
}
public function setBar($val) {
if ($this->isRestricted('setFoo')) {
throw new \Exception('It is impossible to modify bar property in '.$this->context.' context!');
}
$this->bar = $val;
}
protected function isRestricted($methodName) {
return array_key_exists($methodName, $this->restrictedMethods);
}
}
If you are trying to write good OOP, then "Interface Segregation" from the SOLID principle may be useful to you.
interface IBase
{
public function doMethod1();
public function doMethod2();
public function doMethod3();
}
interface IFoo extends IBase
{
public function setFoo($val);
}
interface IBar extends IBase
{
public function setBar($val);
}
function doWork(IBase $obj, $val)
{
$obj->doMethod1();
$obj->doMethod2();
$obj->doMethod3();
if ($obj instanceof IFoo) {
$obj->setFoo($val);
}
if ($obj instanceof IBar) {
$obj->setBar($val);
}
}
I doubt this example is exactly what you need, but I will use it to explain the basic idea.
A class should only have a "Single Responsibility". What that responsibility encompasses can vary however, so in general it is best to limit a class's functionality to a single area of concern as best you can.
If you want to follow "Liskov substitution", then throwing exceptions like that in your functions simply because the "context" was irrelevant, violates this principle.
Enter "Interface segregation":
By implementing an interface, you are (to a certain extent) guaranteeing to the caller of the implemented methods, that those methods will work. By excluding them, you are telling the caller that those methods don't exist.
In the example, the doWork function expects an instance of IBase, and safely calls the methods of that interface. After that, it runs introspection of the object to determine if other "applicable" methods are available.
The goal behind interface segregation is to limit the amount of unneeded features a class is forced to implement, so for you, if the context is public, it shouldn't need the setFoo method.
A clean solution would be to have an ObjectFactory class that creates different objects based on a $context parameter, and having two separate classes (with a common base class) that allows writing to the appropriate properties.
Please find below a possible implementation for your schema:
/**
* Base class that allows subclasses to define which properties are
* writable via setters. Subclasses must not add public setters,
* otherwise the mechanism within this class will not work; subclasses
* can add protected setters, though
*/
class PropertyRestricter {
// only properties listed here are writable
// to be initialised by subclasses
protected $writableProperties;
public function __construct() {
// default implementation allows no writable properties
$this->writableProperties = array();
}
public function __call($method, $arguments) {
$matches = false;
// check if a setter was called, extract the property name
// there needs to be at least one argument to the setter
if(count($arguments) && preg_match('/^set([A-Z][a-zA-Z0-9_]+)$/',$matches)) {
$propName = $matches[1];
$propName[0] = strtolower($propName[0]);
// update the property with the given value
// or throw an exception if the property is not writable
if(is_array($this->writableProperties) && in_array($propName, $this->writableProperties)) {
$this->{$propName} = $arguments[0];
} else {
throw new Exception(get_class() . ": $propName is not writable");
}
} else {
// not a setter, nor a public method
// maybe display a user error
}
}
}
/**
* Common properties for the actual classes
*/
class BaseObject extends PropertyRestricter {
protected $foo, $bar;
}
class PublicObject extends BaseObject {
public function __construct() {
parent::__construct();
$this->writableProperties = array('foo');
}
}
class APIObject extends BaseObject {
public function __construct() {
parent::__construct();
$this->writableProperties = array('bar');
}
}
class ObjectFactory {
public function createObject($context) {
switch($context) {
case 'public': return new PublicObject();
case 'api': return new APIObject();
default: return null;
}
}
}
The root of the objects is the PropertyRestricter class that allows subclasses to define which properties are writable. It makes use of the magic method __call() in order to be able to intercept setter calls and to validate the attempt to write to the property. However please note that this works only if subclasses don't add public setters for their properties.
The next level is the BaseObject class, which only defines the two properties, in order to reduce code redundancy.
The last level contains the two classes that get instantiated by the ObjectFactory: PublicObject, 'APIObject. These classes simply initialise thewritablePropertiesarray, as the rest of the work is done by thePropertyRestricter` class.
This is also a scalable solution, as it allows adding as many properties and subclasses as needed, each subclass defining its property writing rules.
Also the property update within the __call() method can be customised, I implemented it in the simplest way by directly setting the property. Actual setters can be used in subclasses and __call() can be updated to call the setters, with the mention that the setters need to be protected in order for the mechanism to work.
I am using PHP.
As properties defined within the core of a class must be static, I have to create one property in the constructor to allow me to create it with a dynamic name.
Example
final class User extends Z
{
}
Abstract Class Z
{
function __constructor()
{
$x = get_called_class() . 'Id';
$this->$x = null;
}
}
If we var_dump() obj User we would have
object(User)#1 (1) {
["UserId"]=>
NULL
}
I want to set property A as a protected type.
How can I do this?
Or is there a better way to set the name of my dynamically named property?
The best you can probably do is use magic getter/setter methods and an array of properties:
<?php
abstract class Z
{
private $properties = array();
function __construct()
{
$x = get_called_class();
$this->$x = null;
}
public function __set($prop, $val)
{
$this->properties[$prop] = $val;
}
public function __get($prop)
{
return $this->properties[$prop];
}
}
class A extends Z
{
}
var_dump(new A());
Note that the property is private, child classes will have to go through the __get and __set methods.
You could also restrict dynamic properties to only be the called class name.
<?php
abstract class Z
{
private $classprop;
function __construct()
{
$x = get_called_class();
$this->$x = true;
}
public function __set($prop, $val)
{
if ($prop !== get_called_class()) {
throw new \UnexpectedValueException('Cannot Set Dynamic properties Other than Class Name');
}
$this->classprop = $val;
}
public function __get($prop)
{
if ($prop !== get_called_class()) {
throw new \UnexpectedValueException('Cannot Get Dynamic properties Other than Class Name');
}
return $this->classprop;
}
}
class A extends Z
{
}
I would encourage you to think pretty carefully about why you need dynamic properties like this.
The easiest answer would be don't - just use some generic base property, like protected $Id; and save the trouble.
If you really must have "dynamic" properties in class extensions, probably the simplest would be to declare the property in the extending class:
final class User extends Z {
protected $UserId;
}
Then your code in Z will pick out this protected property. It's psudo-dynamic, since the property name is determined by the coder, and the script only "finds" it when the constructor is run, but if your property name is already determined by something fixed at compile-time, such as the class name, there's functionally no difference.
For truly dynamic property creation, you'd have to add in a runkit, an extension that allows you to programmatically change classes, methods, properties, and functions from within the script itself. A good one seems to be this one by Demitry Zenovich. Unless you have some truly complex functions to carry out to justify the time working with it, though, it ain't going to make your life easier.
Using PHP, how can a class determine if a subclass has overridden one if its methods?
Given the following two classes:
class Superclass {
protected function doFoo($data) {
// empty
}
protected function doBar($data) {
// empty
}
}
class Subclass extends Superclass {
protected function doFoo($data) {
// do something
}
}
How can a method be added to Superclass that will perform different actions depending on which of its methods have been overridden?
For example:
if ([doFoo is overridden]) {
// Perform an action without calling doFoo
}
if ([doBar is overridden]) {
// Perform an action without calling doBar
}
With ReflectionMethod::getPrototype .
$foo = new \ReflectionMethod('Subclass', 'doFoo');
$declaringClass = $foo->getDeclaringClass()->getName();
$proto = $foo->getPrototype();
if($proto && $proto->getDeclaringClass()->getName() !== $declaringClass){
// overridden
}
If the classes match, it wasn't overridden, otherwise it was.
Or if you know both class names, simply compare $declaringClass against the other class name.
Say I have an abstract class Entity, I also have a handful of abstract classes Provider, Model, Service,... all extending directly Entity. Finally, i have a last set of concrete classes ConcreteProvider, ConcreteModel, ... that extends respectively Provider, Model, ...
On each instance of Concrete* I want a method getId() that when called on an instance of a class which extends Provider ( like ConcreteProvider ), it returns the string 'Provider', and so on for Model and ...
The only way I found to achieve that is :
abstract class Entity {
abstract function getId ();
}
abstract class Provider extends Entity {
function getId () {
return __CLASS__;
}
}
abstract class Model extends Entity {
function getId () {
return __CLASS__;
}
}
class ConcreteProvider extends Provider {
}
class ConcreteModel extends Model {
}
$cp = new ConcreteProvider();
echo $cp->getId() . "\n"; // returns the string Provider
$cm = new ConcreteModel();
echo $cm->getId(); // returns the string Model
Code duplication is here obvious. I'm looking for the same behaviour without duplicate. I guess it would be nice to put the method into Entity.
Have you an idea ? How would you do that ?
// Edit
Of course, there is a way to move getId into Entity :
abstract class Entity {
function getId () {
$class = get_called_class();
while ( __CLASS__ !== get_parent_class($class) )
$class = get_parent_class($class);
return $class;
}
}
But there is a lot of computation for, imo, nothing worth...
I'm not a big fan of magic, thus I recommend the straight-forward way
const ID = 'Provider';
public function getId () {
return self::ID;
}
Or just
function getId () {
return 'Provider';
}
but with the constant its easier to compare
$x->getId() == Provider::ID;
Here is the best I found, using my second proposition, and adding to it memoization.
abstract class Entity {
private $subType = '';
function getId () {
if ( $this->subtype )
return $this->subType;
$class = get_called_class();
while ( __CLASS__ !== get_parent_class($class) )
$class = get_parent_class($class);
return $this->subType = $class;
}
}
<?php
class Entity {
public static function getId() {
return get_called_class();
}
}
class Model extends Entity {
}
class Provider extends Entity {
}
$a = new Model();
echo $a->getId(); //returns Model
$b = new Provider();
echo $b->getId(); //returns Provider
$c = new Entity();
echo $c->getId(); //returns Entity
Using late static binding. Your php version should be greater than 5.3.
http://www.php.net/manual/en/function.get-called-class.php
You should use PHP magic method __toString() for the classes you want to get class names for, then when you typecast the object as a string, it will return the class name:
abstract class Provider extends Entity {
public function __toString() {
return __CLASS__;
}
}
abstract class Model extends Entity {
public function __toString() {
return __CLASS__;
}
}
$cp = new ConcreteProvider();
var_dump($cp); // Outputs object
// Force cast of $cp object to a string, which calls __toString()
var_dump((string) $cp); // Outputs Provider
// Vanilla echo forces object cast to string
echo $cp; //Outputs Provider
$cm = new ConcreteModel();
var_dump($cm); // Outputs object
// Force cast of $cp object to a string, which calls __toString()
var_dump((string) $cm); // Outputs Model
// Vanilla echo forces object cast to string
echo $cm;
With this approach you don't need to force a getId method upon child classes extending the parent Entity class.
Also, Using a getId() for this functionality is mis-leading imo, 99% of the time when I call on a classe's getId() method, I expect an int representing a specific instance of an object, fetched from a store (database, cache, flat-file).
Update 2014:
If you are running PHP 5.4+ you could use a trait to share this function between Models and Providers.
What is to stop you from using the type system? Where you might currently call:
if ($object->getId() == 'Provider') {
// provider specific code
}
Can't you use:
if ($object instanceof Provider) {
// provider specific code
}
Admittedly using type conditionals like this defeats the purpose of polymorphism. I might be able to offer better advice with more context.
I would like to have a PHPUnit Mock which executes a method like normal, but then modifies the return value in some way before the function returns.
What I have
I have a set of derived classes, similar to below:
abstract class Base
{
abstract protected function getUrl();
public function callUrl() {
$url = $this->getUrl();
// some code to call the URL here
}
}
class Foo extends Base
{
protected function getUrl() {
return "http://www.example.com/Foo";
}
}
class Bar extends Base
{
protected function getUrl() {
return "http://www.example.com/Bar";
}
}
Please note the classes I have are much more complex, and some of the items I have to test have side-effects (such as writing to a database, etc).
The naive, duplicate code approach
If I only had a single derived class (eg; Foo), then I could do the following:
class FooMock extends Foo
{
protected function getUrl() {
return parent::getUrl() . "?sandbox";
}
}
class theTest extends PHPUnit_Framework_TestCase
{
public function testIt() {
$mock = new FooMock();
// assert something
}
}
Unfortunately, this means I would need a specific "Mock" class for each derived class I want to test, all of which perform exactly the same function.
The preferred approach
Instead, I would like to be able to do something like the following:
function callback ($returnValue) {
return $returnValue . "?sandbox";
}
class theTest extends PHPUnit_Framework_TestCase
{
private $mock;
public function testFoo() {
$this->mock = $this->getMockBuilder('Foo')->getMock();
$this->setupMock();
// assert something
}
public function testBar() {
$this->mock = $this->getMockBuilder('Bar')->getMock();
$this->setupMock();
// assert something
}
public function setupMock() {
$this->mock->expects($this->any())
->method('getUrl')
->will($this->postProcessReturnValue('callback'));
}
}
Is this at all possible with PHPUnit?
Update: It was suggested I have an instance of the original class, and an instance of the mock class. Use the original class to get the original return value and modify that. This modified value is then used as the return for the Mock. This is not a feasible way to go about things as the classes are more complex (they have side effects such as writing to the DB).
An example where this would not work;
class Foo extends Base
{
$id = 0;
public function saveToDB() {
$this->id = saveToDBAndReturnId();
}
protected function getUrl() {
if ($this->id > 0) {
return "http://www.example.com/".$this->id;
}
throw new Exception("No ID");
}
}
$foo = new Foo();
$foo->saveToDB();
$url = $foo->getUrl();
Obviously the returned URL would be different between multiple calls. I could always mock saveToDB, but that's starting to feel dirty when all I want to do is post-process the result of getUrl.
PHPUnit allows you to define a stub method that will use a callback to determine what to return.
$this->mock->expects($this->any())
->method('getUrl')
->will($this->returnCallback('callback'));
You can define your callback to call the original class method and modify the return value.
Of course, using mock objects in this way more or less defeats the purpose of having them be "mock" objects, since the mock objects will now rely on the underlying implementation.