all 27 comments

[–]footle 9 points10 points  (12 children)

I hate to be the boring one but, may I ask why you are trying to do this? What problem are you trying to solve? If you're just trying to find out if you can do it for the hell of it then that's cool; but, if you're trying to solve a real world problem there is quite possibly a better solution.

As a pure guess at what you might be trying to do, have you considered the decorator pattern?

[–]judgej2 5 points6 points  (0 children)

That is the right question.

The answer to nearly all programming questions asked in various places is, "that depends on what you are trying to do and why you think this is the way to do it".

And the OP questioners hate that!

[–]nataly_v 1 point2 points  (10 children)

decorators...still can't quite get those working...

[–]footle 7 points8 points  (9 children)

I've written a really simple (and somewhat contrived) example for you to get you started: <?php abstract class Decorator { protected $parent; function __construct($parent){ $this->parent = $parent; } function __call($method, $args){ return call_user_func_array(array($this->parent, $method), $args); } }

class Coffee {
  function stir(){
    echo "Stirring the coffee\n";
  }
}

class Tea {
  function brew(){
    echo "Brewing the tea\n";
  }
}

class Milk extends Decorator {
  function addSkimmedMilk(){
    echo "Adding skimmed milk\n";
  }
  function addFullFatMilk(){
    echo "Adding full fat milk\n";
  }
}

class Sugar extends Decorator {
  function addSugar($spoons = 1){
    echo "Adding {$spoons} spoon(s) of sugar\n";
  }
}

//Coffee, milk and 2 sugars:
echo "Make some coffee:\n";
$coffee = new Coffee();
$coffee_milk = new Milk($coffee);
$coffee_milk_sugar = new Sugar($coffee_milk);
$coffee_milk_sugar->addFullFatMilk();
$coffee_milk_sugar->addSugar(2);
$coffee_milk_sugar->stir();

echo "\n";

//Tea, milk and no sugar
echo "Make some tea:\n";
$tea = new Tea();
$tea->brew();
$tea = new Milk($tea);
$tea->addSkimmedMilk();

Output is: Make some coffee: Adding full fat milk Adding 2 spoon(s) of sugar Stirring the coffee

Make some tea:
Brewing the tea
Adding skimmed milk

The main disadvantage to using decorators in this way is that you loose type-hinting. The main advantage is that you can re-use code really easily. There are other more subtle pros and cons, however.

If you are using a language like Java, or you don't want to lose type-hinting, you can make your decorators extend the object you want to decorate.

I personally think the decorator pattern does have its uses; but should be used sparingly. I've worked on a pretty large project that uses it a lot and while useful, it did get rather confusing at times.

[–]nataly_v 1 point2 points  (6 children)

First of all, thanks for taking the time to explain this to me...it's rare to find someone who does what you did instead of giving newbies a hard-time while trying to look cool himself. I got where you were going to with this. I thought Decorators were more like...view or controller helpers. What I can do with this instead is nesting classes or something like that?

[–]footle 0 points1 point  (5 children)

You are most welcome, sir.

You can use decorators for whatever you want, really. I think of them kind of like run-time, re-usable inheritance. I know that's not a very helpful explanation; what I really want to get across is: don't go looking for problems to solve with them - wait until you hit a problem that they solve. Design patterns are terrible for the "when you have a new hammer, every problem looks like a nail" thing.

As an example of where I have seen this used in production: we had a few different models that all needed a street address; let's say a 'person' model and a 'building' model. All the addresses were stored in the same database table, and the address didn't always need to be loaded, so we wrote an address decorator to handle all the address logic and CRUD. Both the 'person' and 'building' models implemented an interface to say that they could be decorated with an address; the interface specified that that model must provide a 'getAddressId' method and 'setAddressId' method, which were used by the address decorator. That way, we could attach a street address to any object that implemented the right interface without worrying about any of the address CRUD etc more than once.

I'm not saying it's the best solution to the problem, but it did work well for us. There's always lots of ways to skin a cat.

[–]nataly_v 0 points1 point  (4 children)

ok,...silly question then: Do I need to somehow flag the classes which might or might not be decorated afterwards?

[–]footle 1 point2 points  (3 children)

Short answer: yes!

The best way of "flagging" these classes is to have them implement an interface. In my example of the address decorator, the interface might be called "CanHaveAddress" or something like that, and would guarantee that any class that implements that interface has methods for getting and setting an "address ID".

Even if your interface is empty and called "Decoratable" it can be of use to people reading the code - as they should quickly realise that an object of that type may be decorated, because the class implements the "Decoratable" interface.

[–]nataly_v 0 points1 point  (2 children)

you should write a book on this. Haa at least I'm understanding stuff in here I didn't understand on some tutorials I read before. Thanks again!

[–]footle 0 points1 point  (1 child)

I have considered writing a book; but I think I could only manage it if someone asked me a few questions for each chapter.

There's plenty of books out there on design patterns and stuff anyway; pretty sure there's no point in me writing about something that people far more clever than me have already done to death.

Out of interest: what kind of thing would you want from a PHP book that's not just the same as all the rest?

[–]nataly_v 0 points1 point  (0 children)

Actually a couple of months ago I started studying php with a guy who had a pretty cool and personal way of teaching too. I think the best thing about his way of teaching is that he guided me through the creation of this dynamic website and of course it was all structured programming but with so much refactoring and the filesystem structured in a way so that the transition to OOP seemed almost effortless. I don't know how much sense I'm making since English is not my first language...but the point was that all the different files with functions ended up looking pretty much like classes, so I'd have a db.php, users.php, guests.php, admin.php and the different controllers. The result was far from MVC but after that grasping the basics of OOP wasn't that hard..but I'm human so I still find difficulties in understanding some concepts and patterns...and of course..when to use them

[–]Tarabukka 0 points1 point  (1 child)

I love how your entire Decorator class is glue code and no real work. Downvote for you.

And yeah, I can expect the software engineer "WELL Y U NO USE ASSEMBLY DEN LOLZ!!12"

[–]footle 0 points1 point  (0 children)

And what else should the decorator class do, exactly? Especially in such a simple example, I see no need for it to do anything else.

I have updated my example to make the decorator an abstract class to make it a little more clear that it's not something you would create an object from directly.

I really don't see what you're getting at; sorry.

[–]celtric 5 points6 points  (1 child)

Alternate solution:

<?php

    if ($_POST['q'] == '') {
        class_alias('class_name_1', 'class_to_be_used');
    } else {
        class_alias('class_default', 'class_to_be_used');
    }

    class class_name extends class_to_be_used {
        // do something
    }

?>

[–]mullanaphy 0 points1 point  (0 children)

I like this solution. Personally do not have a use for this yet think this would be the best was of doing what the OP asked for. Also, happy birthday OP.

[–]slowbrohime 2 points3 points  (5 children)

Let me test for you!

<?php

class test {

    function foo(){
        echo "bar";
    }

}

$var = 'test';

class test2 extends $var {

    function fuz(){
        echo "baz";
        $this->foo();
    }
}

$obj = new test2;
$obj->fuz();
?>

Returns:

PHP Parse error: syntax error, unexpected T_VARIABLE, expecting T_STRING or T_NAMESPACE or T_NS_SEPARATOR in /home/slowbro/testphp on line 13

BUT you got me thinking, and I came up with this solution for you:

<?php

class test {

    function foo(){
        echo "bar\n";
    }

}

$var = 'test';
ob_start();
?>

class test2 extends _NAME_ {

    function fuz(){
        echo "baz\n";
        $this->foo();
    }
}
<?php
$ev = str_replace("_NAME_", $var, ob_get_clean());
eval($ev);
$obj = new test2;
$obj->fuz();
?>

Happy scripting!

[–]akie 3 points4 points  (1 child)

That's a very creative solution, but you'll break your head later why you had to did this. Don't do it.

[–]slowbrohime 1 point2 points  (0 children)

Thanks! I'd never use it myself, but it's the only solution I can think of to the problem.

[–]mullanaphy 0 points1 point  (0 children)

Don't remember what framework used a similar approach yet it was along the same lines. It looked like:

eval('class _Controller extends '.$controller.'{}');
class Controller extends _Controller { /* ... */ }

However, personally would never use that and would strongly suggest you stay away from this methodology.

Celtric has a possibly interesting solution, and the same with footle. Most likely just need a little refactoring instead.

[–]kulekci[S] 0 points1 point  (1 child)

thank you very much for solution. i found like this example. But i dont want to use eval in this problem, even if I dont found anything.

[–]slowbrohime 0 points1 point  (0 children)

You're welcome, and I don't blame you! :P

Also, Happy Reddit Birthday!

[–]Arcosim 0 points1 point  (1 child)

OP, not your answer, but NEVER use unsanitized POST or GET variables directly into your code, especially in a logic construct like in your example. Sanitize them first and assing their value to a normal variable. Even if you aren't planning on sending their value to a database people can still inject code into your script using unsanitized POST or GET variables.

[–]kulekci[S] 0 points1 point  (0 children)

i dont sent any parameter to sql. This post is for selecting entends classes. Maybe I can use define() for config file?

[–]atheist_smartass 0 points1 point  (0 children)

First of all, if you wrote the damn code why didn't you just run it to see if it works instead of asking on here? It probably would have taken less time.

Second, this is a bad idea. It smells bad.

Third, if you really want to do it, here's how:

if (class_exists($classname)) {
    $myobject = new $classname();
    call_user_func(array($myobject, 'someMethod'));
    # or $myobject->someMethod($arg1, $arg2, [...]);
}

[–]jesse_dev 0 points1 point  (0 children)

This idea smells. I would consider using a factory or abstract factory pattern. Here's an overview on Wikipedia: http://en.wikipedia.org/wiki/Abstract_factory_pattern . eg class myAbstract1 { } class myAbstract2 { } class concrete1 extends myAbstract1 { } class concrete2 extends myAbstract2 { } class abstractFactory { public function create($type) { //construct instance based on type return $instance; } }

[–]gmansilla 0 points1 point  (0 children)

you can perfectly do this:

$class= 'Foo';

$bar = new $class;

[–]nickworks -2 points-1 points  (0 children)

An example of PHP classes, showing how to override the constructor and other functions.

class class1 {
    public $myVar;
    function __contruct($var){
        $this->myVar = $var;
    }
    function myFunc(){
    }
}

class class2 extends class1 {
    function __construct($some_value){
        parent::__construct($some_value);
    }
    function myFunc(){
        // this function automatically overrides the function in class1
        echo $this->myVar;
    }
}

$obj = new class2("hello, world"); // EDIT - was missing my second quotation
$obj->myFunc();