As the title says, I'm wanting to create an instance of a class from within a static method of the same class. I've figured out so far is that I can by doing something like this:
class Foo{
public $val;
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Which therefore lets me do this.
$obj = Foo::bar("some variable");
Which is great.
So now the questions. Is there an开发者_开发百科 easier way of doing this that I'm not aware of, or any shortcuts to achieving the same result? Are there any advantages or disadvantages of creating an instance in this fashion?
Thanks.
They way you're doing it is fine. There are a few other things that can make your life easier that you can do as well.
Don't hardcode the class name. If you're on 5.3+, use the keyword
static
. That way, if you extend the class, the new function can instantiate that one as well:public static function bar($var) { $obj = new static(); $obj->var = $var; return $obj; }
Then you can use it in any extending class without needing to override anything.
Figure out if
$var
should be passed in through a constructor rather than set after construction. If the object depends upon it, you should require it.public function __construct($var) { $this->var = $var; }
That way you can't instantiate the object without setting the variable.
Enforce the instantiation of the class through the static method. If you're doing anything in there that you need to do, then make the constructor either protected or private. That way, someone can't bypass the static method.
protected function __construct() {} private function __construct() {}
Edit: Based on your comment above, it sounds to me like you're trying to implement the Singleton Design Pattern. There's tons of information out there about why it's not a great idea and the bad things it may do. It has uses as well.
But there are a few other patterns that may be of use to you depending on what you're doing exactly.
- You can use the Factory Method if you're trying to create different objects using the same steps.
- If all of the objects start off the same and then are customized, you could use the Prototype Pattern.
- You could use an Object Pool if it's particularly expensive to create your object.
But one thing to consider, is that in PHP objects are pretty light weight. Don't try to avoid creating a new object just for that overhead. Avoid doing heavy things like database queries or filesystem accesses multiple times. But don't worry about calling new Foo()
unless foo
's constructor is particularly heavy...
This looks like a simple factory method pattern.
You have a nice advantage: suppose that in the future you want to start using a different implementation (but that does the same thing). Using a factory you can change all the objects that are created in many places of a complex system simply by changing the creator method. Note that this would work easier if you used an external class (as is in the first link below).
Keeping it as you have now, you can also subclass this class and override the method to create a more complex object. I don't think this is what you want to achieve in here.
Anyway, this is good to enable Test Driven Development, abstraction and lots of other good things.
links:
- Php patterns
- Factory method pattern on wikipedia
If you're just creating an object, this isn't very usefull. You could just call a constructor. But if you're doing something more complicated (like you're starting with some sort of singleton pattern but haven't included all the details in this example), then:
This sounds about right. If you want to prevent objects created in the default way like this:
$obj = new Foo("Some Variable");
You can add a private constructor:
class Foo{
public $val;
private __construct(){}
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Now you enforce people to use your static class. The need to set the val in the function might be gone, so you could even add the value-parameter to your private constructor but do the other things (that you presumably want to do, like check for some sort of singleton pattern) in your 'bar' function
Super late but found this useful.
A good example of this in the wild is this static method from Audi's UI library returning an Array
of instantiated TextField
classes from within TextField
's static
method upgradeElements
.
/**
* Class constructor for Textfield AUI component.
* Implements AUI component design pattern defined at:
* https://github.com/...
*
* @param {HTMLElement} element The element that will be upgraded.
*/
export default class Textfield extends Component {
/**
* Upgrades all Textfield AUI components.
* @returns {Array} Returns an array of all newly upgraded components.
*/
static upgradeElements() {
let components = [];
Array.from(document.querySelectorAll(SELECTOR_COMPONENT)).forEach(element => {
if (!Component.isElementUpgraded(element)) {
components.push(new Textfield(element));
}
});
return components;
};
constructor(element) {
super(element);
}
...
See the rest in the repo https://github.com/audi/audi-ui/blob/master/src/textfield/textfield.js#L25
精彩评论