I'd like to accomplish something like this: Call a method, say "turn", and then have "turn" applied differently to different data types, e.g., calling "turn" with a "screwdriver" object/param uses the "turnScrewdriver" method, calling "turn" with a "steeringWheel" object/param uses the "turnSteeringWheel" method, etc. -- different things are being done, but they're both called "turn."
I'd like to implement this so that the calling code needn't worry about the type(s) involved. In this example, "turn" should suffice to "turn" a "screwdriver", "steeringWheel", or whatever might need to be "turned."
In C++ I'd do this with overloading -- and C++ would sort things out based on the datatype/signature -- but this doesn't work in PHP.
Any suggestions as to where should I begin? A switch statement is obvious, but I'm thinking there must be a (more elegant) OO solution. No?
TIA
I read davethegr8's solution but it seems one could do the same thing with stronger typing:
<?php
interface Turnable
{
public function turn();
}
class Screwdriver implements Turnable
{
public function turn() {
print "to turning sir!\n";
}
}
class SteeringWheel implements Turnable
{
public function turn() {
print "to everything, turn, turn turn!\n";
}
}
function turn(Turnable $object) {
$object->turn();
}
$driver = new Screwdriver();
turn($driver);
$wheel = new SteeringWheel();
turn($wheel);
$obj = new Object(); // any object that does not implement Turnable
turn($object); // ERROR!
PHP does permit you to use a type hint for the parameter, and the type hint can be an interface name instead of a class name. So you can be sure that if the $object implements the Turnable interface, then it must have the turn() method. Each class that implements Turnable can do its own thing to accomplish turning.
I think this will work...
function turn($object) {
if(method_exists($object, 'turn'.ucwords(get_class($object))) {
$fname = 'turn'.ucwords(get_class($object));
return $object->$fname();
}
return false;
}
You need to check the PHP Manual for instructions here
Related
I'm a bit lost here because I want to do something that is very easy in Java but seems a bit complicated in PHP.
We are building an SDK for our product and in Java, we have this one class that must not (!) be instantiated by the user (i.e. the coder), since there are several constraints regarding it's integrity. So we've built that as a nested class "X" inside of the "XFactory" and you will get an instance of X by calling XFactory.buildMeMyX(); - Easy...
Now PHP does not support nested classes at all, and I wonder how to apply the same here. In Java, X's constructor is hidden (private), so only XFactory can call it.
In PHP, it looks like I will have to make __construct() public and move the nested class X out of XFactory. Hence, the user will be able to create an instance without the Factory.
Now - I COULD move the factory functionality to X itself and move all the stuff there, but this would kind of break the design of the SDK. Is there a useful way to do such things in PHP after all?
For PHP 5.x you already described your options, there are no private/protected classes or inner classes at all, so there is no further way to restrict instantiation.
However, with PHP 7 this is going to change.
There are still no nested classes (although we might get them in the future, see: https://stackoverflow.com/a/31454435/664108), but you could instantiate an anonymous class and only provide the consumer with its interface like this:
class XFactory
{
public function buildMeMyX()
{
return new class() implements XInterface {
public function doWhatEverAnXCanDo()
{
// X X X
}
// ...
};
}
}
interface XInterface
{
function doWhatEverAnXCanDo();
}
As the others have said, there currently is no clean way to implement this behavior in PHP. In my opinion, the only valid use case for private constructors are factories inside the class that implement that factories.
Whenever you try to get around that use case it gets messy. No one should ever try to invent clever ways to bypass PHP's language limiations.
I just violated that rule by myself just to prove it is indeed possible. But please refrain from using that in production, or better: using it anywhere. I will try to find some bulletproof arguments for that suggestion and edit the answer afterwards.
<?php
class Dependency {}
class SomeClass {
protected $dep;
private function __construct(Dependency $dep)
{
$this->dep = $dep;
}
public function doSomething()
{
var_dump($this->dep);
echo "Doing Stuff and even having dependencies";
}
}
class SomeClassFactory {
public function buildSomeClass()
{
return $this->instantiateSomeClassWith(new Dependency);
}
protected function instantiateSomeClassWith()
{
$reflectionClass = new ReflectionClass('SomeClass');
$someClass = $reflectionClass->newInstanceWithoutConstructor();
$constructor = $reflectionClass->getConstructor();
$constructorClosure = $constructor->getClosure($someClass);
call_user_func_array($constructorClosure, func_get_args());
return $someClass;
}
}
$factory = new SomeClassFactory();
$someClass = $factory->buildSomeClass();
$someClass->doSomething();
?>
Output: object(Dependency)#2 (0) { } Doing Stuff and even having dependencies
The theory is simple. The constructor of the class that will be built via the Factory is made private. We make use of reflection within the factory to create an instance of the class without invoking the constructor.
Once we have an instance, we grab the closure of the constructor and invoke it via call_user_func_array(). That way you can make use of Dependency Injection just as you would if the constructor was public.
As I said before. That way is a single smell. By creating an object without invoking it's constructor, there is no real way to validate an objects state upon creation
This is a proof of concept, but the concept sucks.
There is no native way to do so, yet. However, if you really want to "enforce" that your class is only created from your factory class, there is a little "hackish" way to do so limiting the instantiation by inistantiating class.
class X
{
function __construct()
{
new Y();
}
}
class Y
{
function __construct()
{
$trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
if (!isset($trace[1]['object']) || !($trace[1]['object'] instanceof X)) {
throw new \RuntimeException('This is a private class');
}
}
}
new X(); // All is fine
new Y(); // Exception
Please note that there is no "real" way to protect the class from being instantiated from elsewhere even using this approach - it still can be done via reflection by bypassing the constructor, or simply modifying your source.
I have the following code
class Model_MyAbstractClass {
}
class Model_MyClass extends Model_MyAbstractClass {
}
interface doStuff {
function update(Model_MyAbstractClass $model);
}
class Mapper_MyClass implements doStuff{
function update(Model_MyClass $model){
}
}
So why doesn't this work in PHP? Model_MyClass is still a Model_MyAbstractClass.
I have 5 classes (maybe I'll have more) with similar methods. The whole difference is that each mapper has some model, all of them extend Model_MyAbstractClass.
If indeed there is no way of doing this, the only solutions left are: make an interface for each of them, with the only differences being the params (not DRY at all).
Check in each of the functions if the Model_MyAbstractClass is instance of Model_MyClass needed and throw an error - which seems like a silly strategy since I should be requiring explicitly the needed type of parameter.
It is normal, that this is not working.
Your interface let assume, that you can pass any Model_MyAbstractClass to this function:
function update(Model_MyAbstractClass $model);
Here, you expect only a Model_MyClass:
class Mapper_MyClass implements doStuff{
function update(Model_MyClass $model){
}
}
Sure, Model_MyClass is an instance of Model_MyAbstractClass. But the interface would assume, that you also can pass the class Model_SomeOtherClass which is extended from Model_MyAbstractClass.
Summary: You should be able to handle ANY Model_MyAbstractClass NOT ONLY Model_MyClass
What you possible Need:
class Mapper_MyClass implements doStuff
{
function update(Model_MyAbstractClass $model)
{
//Do stuff on Model_MyAbstractClass
//...
if ($model instanceof Model_MyClass) {
//Do additional stuff on Model_MyClass
//...
}
}
}
Maybe you running into the same problem like me, which can be easily solved via C# and Java. For me it was, i wanted a Generic Base Class. So something like this:
abstract class Foo<T> {
function update(T $model)
}
class Bar extends Foo<Model_MyClass> {
}
This is current not possible with plain PHP, but Facebook's Hack made it possible. Problem is, this was no option for me, but maybe for you. I have done it with the way of using the instanceof as described above.
Your problem is not related to PHP, but is more of a misunderstanding how interfaces work in OOP concept.
From your code, interface doStuff has a method which takes Model_MyAbstractClass as its parameter, means the parameter instance will always be displayed as Model_MyAbstractClass and not anything else, doesn't matter if the given instance is instance of Model_MyAbstractClass, like in your example.
In an OOP language, such as Java, you will receive an error like this:
The method update(Model_MyAbstractClass) of type Mapper_MyClass must override or implement a supertype method
However, in PHP you can do instanceof checks, and in OOP languages you can cast to Model_MyClass
I'm probably missing something obvious here as this is basic functionality in other OOP languages, but I'm struggling with PHP way of doing this. I understand that PHP is not "true" OOP language, but still...
What I'm after is casting an object instantiated as derived class to base class. Something along the lines of:
class Some{}
class SomeMock extends Some {}
function GetSomeMock(){
$mock = new SomeMock();
return (Some)$mock; //Syntax error here
}
I've found some questions with strange request of downcasting objects of base class to derived which is possible with some nasty tweaks, but this basic functionality does not have to be that difficult. What am I missing here?
Edit: It seems that it's always matter what I'm trying to achieve. No problem. GetSomeMock() is a factory method that would return a mock object stub (derived from base class, all properties prepopulated in constructor) with expected properties' values. I would then compare it to another object of base type that is restored from database:
$this->assertEquals($mockObject, $realObject);
This fails instantly as $mockObject and $realObject are of different types. I can imagine there are many workarounds I can implement to achieve the same, but I'd like to keep things as simple as possible.
Ok, the short answer seems to be: This is not possible. PHP knows better than me what type I need.
In PHP you cannot cast to a specific class, I cannot even see any need for that.
You may cast to some native type - string, int, array, object. But not a specific class.
If you need to use some functionality of a base class, you can do it via parent keyword.
class Some {
public function execute(){
echo "I am some" ;
}
}
class SomeMock extends Some {
public function execute(){ //Override the function
parent::execute() ; //Here you can execute parent's functionality and add some more
}
}
Edit:
instanceof operator may come handy. When comparing objects.
For instance:
$object = new SomeMock() ;
$status = ($object instanceof Some && $object instanceof SomeMock); //will return true here ;
Child classes inherit non-private properties and methods.
Let's say, you have your function:
function assertEquals($mockObject, $realObject){
if ($mockObject instanceof Some && $realObject instanceof Some){
//Both objects have the same base class - Some
//That means they must have inherited the functionality and properties of Some class.
}
}
You can do it with an custom function:
private function castParameter(BaseClass $parameters) : DerivedClass {
return $parameters;
}
I did come across use cases when I needed to cast a derived class to its base class. I did the following.
function castToParentClass($derivedClassInstance) {
$parentClassName = get_parent_class($derivedClassInstance);
$parentClassInstance = new $parentClassName();
foreach ($parentClassInstance as $key => $value) {
$parentClassInstance->{$key} = $derivedClassInstance->{$key};
}
return $parentClassInstance;
}
I have a scenario where I'm trying to incorporate several people's PHP work, some of it OOP and some not. I want to pull a library file of functions into a class and have those functions be available to other files that reference the class. I know I can just call the library functions directly, but then I would have to update all of the dependent files to do likewise. Example:
class do_something {
function test_state() {
...
}
if ($this->test_state($var)) {
...
}
}
Where test_state() is identical to the same-named function in the library file, making for redundant code to keep sync'd. That can be changed to:
class do_something {
if (test_state($var)) {
...
}
}
But that creates the aforementioned problem of $this->test_state() not being available to files dependent on the class. What I'd like to be able to do is something like:
class do_something {
public function test_state() = test_state();
if ($this->test_state($var)) {
...
}
}
Obviously, that's a very rough and incorrect example of what I'm trying to do... Is there any way in OOP to make that sort of reassignment, making the method of the same name as the function available within the class?
You can use a workaround to simulate this. In fact you would often want this approach to bolt on closures to objects in PHP. It leverages the magic __call method in PHP to redirect method calls to ordinary functions (beware: no $this available).
class do_something {
function __call($func, $args) {
if (isset($this->$func) && is_callable($this->$func)) {
return call_user_func_array($this->$func, $args);
}
}
}
Then you can "register" functions that you want to allow (or closures) with a simple assignment:
$do_something->function_name = "global_function_name";
$do_something->or_even = array("other_class", "method");
But again, this doesn't make them proper methods as such.
You'd create your base utility class, then extend it. See PHP's manual entry for inheritance for the details. I'm not saying this is the best solution for your exact situation, but I think it answers the question you were trying to get at.
What you're asking for isn't possible directly, but can be faked with a quick (horrible) hack:
class do_something {
public function test_state($param) {
return test_state($param);
}
...
$this->test_state($param);
...
}
Good luck with refactoring!
I have a class that is extended, and its children extended further, an arbitrary number of times. Each extension provides more functionality than its predecessor. The catch is, not all parameters can be provided at initialization time. It is complex enough to warrant passing more configuration options via methods, and then calling some sort of build() or configure() method to ready itself for operation.
The catch is, each class in the hierarchy needs a chance to configure itself, and it needs to cascade from the parent to all of the children.
I successfully do this below, but this solution requires that each class remember to call it's parent's method, otherwise it breaks. I want to remove that responsibility from those who might forget to do such.
How do I modify this code to achieve this?
<?php
class A {
function configure() {
print("I am A::configure() and provide basic functionality.<br/>\n");;
}
}
class B extends A {
function configure() {
parent::configure();
print("I am B::configure() and provide additional functionality.<br/>\n");
}
}
class C extends B {
function configure() {
parent::configure();
print("I am C::configure() and provide even more functionality.<br/>\n");
}
}
$c = new C;
$c->configure();
?>
Output:
I am A::configure() and provide basic functionality.
I am B::configure() and provide additional functionality.
I am C::configure() and provide even more functionality.
Thanks for your help! :)
Without claiming it's pretty, I'd suggest the following. I left out your configure() functions for brevity.
<?php
class A {
function configure_master() {
$init_class = get_class($this);
$ancestry = array();
while (! empty($init_class)) {
$ancestry[] = $init_class;
$init_class = get_parent_class($init_class);
}
for ($i = count($ancestry) - 1; $i >= 0; $i--) {
call_user_func(array($this, $ancestry[$i] . '::configure'));
}
}
}
$c = new C;
$c->configure_master();
I tested this, and it works. call_user_func($ancestry[$i] . '::configure') also works (at least in php 5.3, which is where I tested it), but it relies on the odd (to me) scoping of $this. I'm uncertain whether this is reliable or will carry forward into future versions. The version above "should be" more robust, given my limited knowledge.
If keeping the outside call as configure() is a requirement, I'd suggest renaming all your "configure()" methods to "configure_local()" or some such, and rename "configure_master()" to "configure()". In fact, that's what I'd do to start with, but that's a matter of personal taste.
If you need both the internal method and the external API to remain the same... Then you're stuck, since the base class method is overridden, but I'm sure you knew that.
An arbitrary amount of inheritance? I can't say that's a road I'd want to take, but if you must do so, you might be able to write some type of configure method in the base class that takes the calling (child) class as a parameter. That method would then determine the class type, walk the inheritance tree (pushing each parent class type onto a stack), and then simply run each configure method in succession. I think that the underlying principle might be called reflection, but I'm not sure. (edit: Even less sure, now. Definitely read about it before taking my word.)
The method in the base class might have to be static, though...
I believe that something like this would be possible, but I'm not really up to speed on PHP. I"ll do a little bit of searching and see if syntax and code allows this. Hopefully, though, you can use this idea.
This is the terrible pseudocode form of the idea that I have.
<?php
class A {
static function configure(class) {
//get qualified class name from argument
//get inheritance tree for qualified class name, push each tier into array
//loop: pop array, call configure method for each class in hierarchy
//this might possibly work?
}
}
class B extends A {
function configure() {
print("I am B::configure() and provide additional functionality.<br/>\n");
}
}
class C extends B {
function configure() {
print("I am C::configure() and provide additional functionality.<br/>\n");
}
}
$c = new C;
A::configure($c);
?>
Again, I'll take a look and see if anything in PHP could support this theory. In the meantime, I can live with a few downvotes.
Edit: Actually, this might not have to be static, as long as the method names don't overlap during inheritance. That actually might be a little more elegant, as the object could find its own class name and hierarchy by calling a master configure method.
How about this? (Forgive my PHP syntax if it is imperfect)
<?php
class MyBase {
private $_isChild = true;
public function __construct()
$this->_isChild = false;
}
public function behave() {
if $this->_isChild {
parent::behave();
}
self::doBehave();
}
protected function doBehave()
// do stuff here!
}
}
?>
In your child classes, just implement doBehave.
Max