Php init class method

Static class initializer in PHP

I have an helper class with some static functions. All the functions in the class require a ‘heavy’ initialization function to run once (as if it were a constructor). Is there a good practice for achieving this? The only thing I thought of was calling an init function, and breaking its flow if it has already run once (using a static $initialized var). The problem is that I need to call it on every one of the class’s functions.

Future readers: Here are code details and a discussion of the approach user258626 said he was thinking of doing. Please compare it to the accepted answer. Decide which you’d rather have. Or do one of the other answers; I am suggesting you not blindly adopt the accepted answer. Key point: As a general principle, it is best to pay the coding price once, when you code a class, to keep callers simpler.

I wish we could refactor SO, put the accepted answer into a new question “What does the Singleton pattern look like in PHP?” (for which it’s an excellent answer) and make user258626’s answer (or something like it) the accepted answer to this question.

9 Answers 9

Sounds like you’d be better served by a singleton rather than a bunch of static methods

class Singleton < /** * * @var Singleton */ private static $instance; private function __construct() < // Your "heavy" initialization stuff here >public static function getInstance() < if ( is_null( self::$instance ) ) < self::$instance = new self(); >return self::$instance; > public function someMethod1() < // whatever >public function someMethod2() < // whatever >> 
// As opposed to this Singleton::someMethod1(); // You'd do this Singleton::getInstance()->someMethod1(); 

I want to -1 (but I won’t) for private constructor and getInstance() . You’re going to make it VERY hard to test effectively. At least make it protected so that you have options.

@ircmaxell — you’re just talking about issues with the singleton pattern itself, really. And code posted by anybody on SO shouldn’t be considered authoritative — especially simple examples that are only meant to be illustrative. Everyone’s scenarios and situations are different

20 whole lines. Jeez, doesn’t the author of this answer know that lines of code are a precious resource. They don’t grow on trees ya know!

@PeterBailey Lines of code that don’t accomplish anything but glue are a distraction and makes code less maintainable.

// file Foo.php class Foo < static function init() < /* . */ >> Foo::init(); 

This way, the initialization happens when the class file is included. You can make sure this only happens when necessary (and only once) by using autoloading.

@VictorNicollet, this is ugly. Your code makes init a public method, and it wouldn’t work if it’s private. Isn’t there a cleaner way like the java static class initializer?

Читайте также:  Data transfer object php

@Pacerier if init() does nothing the second time it is invoked, it really doesn’t matter if it is public. static function init() < if(self::$inited) return; /* . */ >

@Pacerier the end result of any constructor or initializer that accepts arguments is ingesting out-of-scope data into the class. you’ve got to handle it somewhere.

This is what I’ve been doing for years, but I recently found out that the Foo::init(); line somehow doesn’t get picked up for code coverage using phpunit.phar —coverage-html

This is incompatible with opcache.preload of PHP 7.4. If the file is preloaded in the preload script, the class will «exist», but not the effects of top-level code in that file — and autoload will NOT require the file because the class exists, and you won’t require it either because it would cause the class to be redefined!

Actually, I use a public static method __init__() on my static classes that require initialization (or at least need to execute some code). Then, in my autoloader, when it loads a class it checks is_callable($class, ‘__init__’) . If it is, it calls that method. Quick, simple and effective.

That would be my suggestion too. I did the same in the past but called it __initStatic() . It feels like a thing PHP needs, knowing Java.

@iautomation Didn’t tried it but this is worth to be placed in an own answer! It is a straightforward and modern approach.

For those working in a professional production environment where composer is bile of the internet. this answer works very well.

i got an error if(is_callable($class_name, «__init»)) < $class_name::__init(); >is this method not useable if i use spl_autoload_register() ?

NOTE: This is exactly what OP said they did. (But didn’t show code for.) I show the details here, so that you can compare it to the accepted answer. My point is that OP’s original instinct was, IMHO, better than the answer he accepted.

Given how highly upvoted the accepted answer is, I’d like to point out the «naive» answer to one-time initialization of static methods, is hardly more code than that implementation of Singleton — and has an essential advantage.

final class MyClass < public static function someMethod1() < MyClass::init(); // whatever >public static function someMethod2() < MyClass::init(); // whatever >private static $didInit = false; private static function init() < if (!self::$didInit) < self::$didInit = true; // one-time init code. >> // private, so can't create an instance. private function __construct() < // Nothing to do - there are no instances. >> 

The advantage of this approach, is that you get to call with the straightforward static function syntax:

Читайте также:  Python and sqlite3 examples

Contrast it to the calls required by the accepted answer:

MyClass::getInstance->someMethod1(); 

As a general principle, it is best to pay the coding price once, when you code a class, to keep callers simpler.

If you are NOT using PHP 7.4’s opcode.cache , then use Victor Nicollet’s answer. Simple. No extra coding required. No «advanced» coding to understand. (I recommend including FrancescoMM’s comment, to make sure «init» will never execute twice.) See Szczepan’s explanation of why Victor’s technique won’t work with opcode.cache .

If you ARE using opcode.cache , then AFAIK my answer is as clean as you can get. The cost is simply adding the line MyClass::init(); at start of every public method. NOTE: If you want public properties, code them as a get / set pair of methods, so that you have a place to add that init call.

(Private members do NOT need that init call, as they are not reachable from the outside — so some public method has already been called, by the time execution reaches the private member.)

Источник

PHP[OOP] — How to call class constructor manually?

Now, the problem is the constructor is called in line 09 But i want to call it manually at line 11-13 Is it possible? If then how? Any idea please?

note that if the parameters of the constructor are passed by reference, then call_user_func_array will fail !!

7 Answers 7

It is not possible to prevent the constructor from being called when the object is constructed (line 9 in your code). If there is some functionality that happens in your __construct() method that you wish to postpone until after construction, you should move it to another method. A good name for that method might be init() .

class Test < public function __construct($param1, $param2, $param3) < echo $param1.$param2.$param3; >> $ob = new Test('p1', 'p2', 'p3'); 

EDIT: I just thought of a hacky way you could prevent a constructor from being called (sort of). You could subclass Test and override the constructor with an empty, do-nothing constructor.

class SubTest extends Test < public function __construct() < // don't call parent::__construct() >public function init($param1, $param2, $param3) < parent::__construct($param1, $param2, $param3); >> $ob = new SubTest(); $ob->init('p1', 'p2', 'p3'); 

This is might make sense if you’re dealing with some code that you cannot change for some reason and need to work around some annoying behavior of a poorly written constructor.

Читайте также:  Процедуры в языке python

Note that if the constructor (__construct method) contains arguments passed by reference, then the function:

I suggest you to use Reflection class instead; here is how you can do so:

// assuming that class file is already included. $refMethod = new ReflectionMethod('class_name_here', '__construct'); $params = $refMethod->getParameters(); $re_args = array(); foreach($params as $key => $param) < if ($param->isPassedByReference()) < $re_args[$key] = &$args[$key]; >else < $re_args[$key] = $args[$key]; >> $refClass = new ReflectionClass('class_name_here'); $class_instance = $refClass->newInstanceArgs((array) $re_args); 

I don’t know if there are some security concerns by using the eval() method, but you could make yourself a function like this:

function CreateObj($className,$params)

And now $ob should now be defined with its correct parameters, i haven’t tested it and maybe there is a mistake in the code, but you get the idea.

If separating instantiation from initialization isn’t strictly a requirement, there are two other possibilities: first, a static factory method.

class Test < public function __construct($param1, $param2, $param3) < echo $param1.$param2.$param3; >public static function CreateTest($param1, $param2, $param3) < return new Test($param1, $param2, $param3); >> $params = array('p1','p2','p3'); if(method_exists($ob,'__construct'))

Or, if you’re using php 5.3.0 or higher, you can use a lambda:

class Test < public function __construct($param1, $param2, $param3) < echo $param1.$param2.$param3; >> $params = array('p1','p2','p3'); $func = function ($arg1, $arg2, $arg3) < return new Test($arg1, $arg2, $arg3); >if(method_exists($ob,'__construct'))

The initialization method described by Asaph is great if for some reason you have a need to logically separate initialization from instantiation, but if supporting your use case above is a special case, not a regular requirement, it can be inconvenient to require users to instantiate and initialize your object in two separate steps.

The factory method is nice because it gives you a method to call to get an initialized instance. The object is initialized and instantiated in the same operation, though, so if you have a need to separate the two it won’t work.

And lastly, I recommend the lambda if this initialization mechanism is uncommonly used, and you don’t want to clutter your class definition with initialization or factory methods that will hardly ever be used.

Источник

Оцените статью