0

Possible Duplicate:
What exactly is late-static binding in PHP?

I would like to build an abstract class that will instantiate it's child class using a static function.

<?php

class A
{
    protected $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public static function create($value)
    {
        /* A must not know about B! 
         * I give that example for the context understanding */
        return **new B**($value);
    }
}

class B extends A
{
}

Of course A has not to know about B.. I do not know if it is possible and I do not want to have to implement the create function in all my 170 subclasses...

Do you think I should use a Factory that would return the instance of one of my 170 classes? That is cumbersome and not very maintainable..

Community
  • 1
  • 1
Alexandre Mélard
  • 12,229
  • 3
  • 36
  • 46
  • Sorry, but I can't understand what are you actually want. – ozahorulia Dec 12 '12 at 19:40
  • It is possible, see the `static` keyword or Late Static Binding. Most likely you're doing it wrong (because you can just use the standard constructor), just saying that so you can later on not say you have not been warned. – hakre Dec 12 '12 at 19:42
  • 2
    As you mentioned, A won't know about any of it's children, nor should it. What is the intended behavior that you're working towards? It does sound like you are looking for a Factory design. – Aaron Hathaway Dec 12 '12 at 19:43
  • 1
    170 subclasses - this is another smell that something is going wrong. Just saying, there can be reasons that are okay, but normally this is a clear sign that you do something wrong. – hakre Dec 12 '12 at 19:44
  • `new static()` would work... but go for a Factory, it's so much nicer. – Wrikken Dec 12 '12 at 19:50
  • I am porting GraphViz in OO design with all Attributes and Attributes type, there are 170 existing attributes with distinct properties, I would like to use a static method to instantiate them easily while I am implementing all the verification checking for each one of them.. So I could do for example: **$graph->setColor(Color::create('yellow));** with Color::create returning an instance of Color that can be either created or retrieved if already instanciated.. – Alexandre Mélard Dec 12 '12 at 19:51
  • Ok, I know the factory pattern, I wanted to avoid the creation of a hundreds lines class – Alexandre Mélard Dec 12 '12 at 19:56
  • `create()` should always create something, because else ... yeah, the name is wrong ;) Also consider the following: `class Color{} class NeonColor extends Color{} Color::create('yellow'); NeomColor::create('yellow');`. Also: I agree, that 170 derived classes smell. Maybe you can combine some, for example an "enum"-type (yes, I know, PHP doesn't know it) field like `$colorStyle = 'Neon'`. (It's a kind of ironic, that you create 170 classes, but 100 lines of code is too much :D Just said) – KingCrunch Dec 12 '12 at 21:13
  • Actually, the 170 classes are not types, they are more attributes, I have another 60 or so AttributesType classes. And don't worry for my hand, I used mainly generated code from the package I am adapting to php... I am coding the ancestors classes but do not want to touch too much the generated code. And yes, I am using Enums for the AttributeTypes classes – Alexandre Mélard Dec 12 '12 at 22:43

3 Answers3

1

I found out a solution, but is it ok?

<?php

class A
{
    protected $value;

    public function __construct($value)
    {
        $this->value = $value;
    }

    public static function create($value)
    {
        $child = get_called_class();
        return new $child($value);
    }
}

I tested it, it's working OK it's really useful in my context.. I do not know if it's ugly, because the parent class doesn't know about the child class, and if the Child class does not exists, the caller will not be allowed to call the create function..

Now, for my practical test, I use:

$graph->setBgcolor(Bgcolor::create('yellow')->valid());

with

 public function setBgcolor(Bgcolor $bgcolor)
Alexandre Mélard
  • 12,229
  • 3
  • 36
  • 46
0

A successful implementation could be like this

class A
{
    protected $value;
public static function create($value)
{
    $type = "NotDivisible";
    for ($i = 2; $i <= 10; $i++) {
         if($value % $i == 0)
         {
             $type = "DivisibleBy".$i;
             break;
         }
    }
    $instance = new $type;
    $instance->value = $value;
    return $instance;
}
}

public class DivisibleBy2 extends A
{
} 

public class DivisibleBy3 extends A
{
} 

public class DivisibleBy5 extends A
{
} 
...

so on.... (I haven't compiled it, sorry for syntax error)

Now as you know static method has nothing to do with the instance of object created because this is why we create a static method at the first place.

So you can put them in any other class and congrats you have implemented the factory design pattern.

However this is not a good implementation.

Badal Singh
  • 918
  • 1
  • 6
  • 13
  • Sorry, that is not what I was waiting for, The parent should not either know about the type of the child class... But thank you for your time anyway :) – Alexandre Mélard Dec 12 '12 at 20:19
0

Another solution would NOT to use the static function and use basic new...

<?php

class A
{
    protected $value;

    public function __construct($value)
    {
        $this->value = $value;
    }
}

Now, for my practical test, I use:

$graph->setBgcolor(new Bgcolor('yellow'));

with

 public function setBgcolor(Bgcolor $bgcolor)

I still think that

Bgcolor::create('yellow')->foo()

looks better than

(new Bgcolor('yellow'))->foo()
Alexandre Mélard
  • 12,229
  • 3
  • 36
  • 46