I have a Java background. So please bear with me.
In a Java application, one way to perform one time initialization is to have an "Initializer Servlet" whose init() method can have one time initialization code. Another more general purpose mechanism is to have a Singleton that initializes on first use - and this mechanism will work in various languages / platforms. What I need to know is how to do it for my PHP webapp.
Should I use the Singleton Pattern? Is there another / better / PHP specific way? Essentially I want have a "Registry" - a single instance of it - which I can then use to create instances of other objects (themselves Singleton or not depends on situation at hand).
The ultimate goal is - I need certain things initialized BEFORE any web request is served by my PHP web application - something an "Initializer Servlet" in Java guarantees me. Maybe there is an "Initializer PHP Page" or something like that?
Thanks in advance
The source PHP, in the regular sense, does not generate an executable program. It is a scripting language. However, you are able to create a singleton.
PHP's nature will not allow you to have a initialization like servlets. In PHP everything will be inside a web request.
As you mentioned, the Registry design pattern can help you to have a place to put your objects, however, they will be recreated on every request.
I do not have a Java background, but a singleton that on construction initiates and returns (or holds as static) other singletons/factories is a common pattern. Because the only defined "entry point" of a PHP application is the file that gets passed to the parser, many PHP applications go to great lengths to redirect to a "bootstrap" script, which prepares the environment and instantiates any singleton and static objects needed by the application. This is then included at the entry point to assure it is available to the entire application.
<?php // this file is bootstrap.php
// ...
class MySingleton {
private static $instance;
private function __construct() {
$this->myFactory1 = new MyFactory1();
$this->myFactory2 = new MyFactory2();
$this->myOtherSingleton = MyOtherSingleton::get();
}
public static function get() {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
// Before we leave, we'll get an instance!
$myBootstrapUtility = MySingleton::get();
// end of bootstrap.php ?>
one would then make sure to require_once('bootstrap.php'); before the rest of application logic.
Of course the actual details are entirely up to you, but this is certainly not an uncommon way of doing what you're after.
Related
I'm not new to PHP or programming at all. But recently I was thinking about website programming in PHP and how easier it was before the OOP. Anyway, I prefer OOP than the old procedural style.
I want to implement a website but it seems I always have to use a global or a static variables. And I'm starting to wonder, how can I do it without those?
Anyway, what I'm talking about is having a class for each "component" of the website.
For example if it was an url shortener website it would be: links, members, database.
What I'm talking about is way more complicated, at least 8 classes.
Anyway, my current approach is the following:
$database = new Database(...);
$links = new Links($db);
$users = new Users($db);
Anyway, for example I want to get all the links a user posted by its ID, I need to use both links and both users components.
Is there any other way I could do this? Any other approach? except passing them as constructor parameters.
You should have the following components:
Business objects, which model and express one particular "thing" in your app:
class Link { ... }
class User { ... }
These don't "do" anything, they're just there to formalise your data structures. These objects have getter and setter methods to get and set individual attributes, which are also validated there:
public function setUrl($url) {
if (!/* validate the URL here*/) {
throw new InvalidArgumentException("$url is not a valid URL");
}
$this->url = $url;
}
Minimum required data is part of the constructor. This ensures your data integrity application-wide. It allows you to assert that when you have an instance of Link, the data expressed by it is minimum valid data for a link.
A database link. Only the bare necessary thing to connect to a database, nothing more, nothing less. A raw PDO or mysqli object will do just fine.
A data-object mapper, which takes a database link and knows how to store business objects in the database and how to retrieve them:
class LinkStorage {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
}
This class has all the various methods of how to retrieve things from your database:
public function getById($id) {
$stmt = $this->db->prepare('SELECT ... FROM ... WHERE id = :id');
$stmt->execute(compact('id'));
if (!$data = $stmt->fetch()) {
throw new RuntimeException("Record with id $id does not exist");
}
return new Link($data['url']);
}
You can have all sorts of different queries encapsulated this way, e.g.:
/**
* Returns all links by a particular user.
* #param User $user
* #return Link[]
*/
public function getAllFromUser(User $user) {
...
}
The usage is then simple:
$db = new PDO(...);
$linkStorage = new LinkStorage($db);
$userStorage = new UserStorage($db);
$user = $userStorage->getById($id);
$links = $linkStorage->getAllFromUser($user);
This kind of code would then be encapsulated in a service class, which holds all the possible "actions" you can do in your app. registerUser(array $data), getLinksOfUser($id), newLinkFromPostData(array $data) etc.
What I've just described is basically the model portion of an MVC-style application. The other two parts would be controllers which call the service methods, and views which output data retrieved from service methods. This approach keeps responsibilities separate and isolated and allows you to put higher-level logic and functionality together like building blocks. Business objects are the lowest building block, their structure needs to be solid and well defined for the rest to work. Data-object mappers just concern themselves with putting those objects into the database and getting them back out again. Services then put all this together in various complex ways and make things happen.
You shouldn't have any cyclic dependencies with this, as responsibilities are well separated. Your individual dependencies may still be somewhat complex. If it becomes too cumbersome to instantiate classes, you'll want to look into Factories:
$factory = new Factory;
$userStorage = $factory->newUserStorage();
All the complexity of instantiation is encapsulated in this factory. One step further are dependency injection containers, who you can configure in, for example, an XML file to specify which class depends on what, and then the DI container will take care of it for you.
I was thinking about website programming in PHP and how easier it was
before the OOP
Well, stick to procedural then. If it is easier to write a well written website in a procedural or functional way then opposed to the ojbect-oriented way. Stick ti what you are used to. OO isn't better then functional. It's just a different approach.
the public void main() in php
In the lanuage Java every piece of software we write has a single entry point. The public void main() method. This method fires up the entire application and passes in the arguments provided on startup. It is also the only exit point in the application. the application ends in this method (unless it crashes).
In php, there is no single entry point. We have a bunch of files that run some scripts that do some more stuff and then somewhere along the line another script decides to return stuff and die();
Dependency injection and how IoC libraries can help
When using dependency injection, it becomes a real pain in the a$$ when creating objects and passing arround the correct instance of a class. We start solving this problem with ugly solutions: Singleton, globals, statics, ... Making our software more and more tightly coupled and harder to maintain.
Inversion of Control can help here. there are some really greate articles on the webz.
You can use autoloading in PHP for a better solution:
http://php.net/manual/en/language.oop5.autoload.php
I'm not new to PHP or programming at all. But recently I was thinking about website programming in PHP and how easier it was before the OOP. Anyway, I prefer OOP than the old procedural style.
I want to implement a website but it seems I always have to use a global or a static variables. And I'm starting to wonder, how can I do it without those?
Anyway, what I'm talking about is having a class for each "component" of the website.
For example if it was an url shortener website it would be: links, members, database.
What I'm talking about is way more complicated, at least 8 classes.
Anyway, my current approach is the following:
$database = new Database(...);
$links = new Links($db);
$users = new Users($db);
Anyway, for example I want to get all the links a user posted by its ID, I need to use both links and both users components.
Is there any other way I could do this? Any other approach? except passing them as constructor parameters.
You should have the following components:
Business objects, which model and express one particular "thing" in your app:
class Link { ... }
class User { ... }
These don't "do" anything, they're just there to formalise your data structures. These objects have getter and setter methods to get and set individual attributes, which are also validated there:
public function setUrl($url) {
if (!/* validate the URL here*/) {
throw new InvalidArgumentException("$url is not a valid URL");
}
$this->url = $url;
}
Minimum required data is part of the constructor. This ensures your data integrity application-wide. It allows you to assert that when you have an instance of Link, the data expressed by it is minimum valid data for a link.
A database link. Only the bare necessary thing to connect to a database, nothing more, nothing less. A raw PDO or mysqli object will do just fine.
A data-object mapper, which takes a database link and knows how to store business objects in the database and how to retrieve them:
class LinkStorage {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
}
This class has all the various methods of how to retrieve things from your database:
public function getById($id) {
$stmt = $this->db->prepare('SELECT ... FROM ... WHERE id = :id');
$stmt->execute(compact('id'));
if (!$data = $stmt->fetch()) {
throw new RuntimeException("Record with id $id does not exist");
}
return new Link($data['url']);
}
You can have all sorts of different queries encapsulated this way, e.g.:
/**
* Returns all links by a particular user.
* #param User $user
* #return Link[]
*/
public function getAllFromUser(User $user) {
...
}
The usage is then simple:
$db = new PDO(...);
$linkStorage = new LinkStorage($db);
$userStorage = new UserStorage($db);
$user = $userStorage->getById($id);
$links = $linkStorage->getAllFromUser($user);
This kind of code would then be encapsulated in a service class, which holds all the possible "actions" you can do in your app. registerUser(array $data), getLinksOfUser($id), newLinkFromPostData(array $data) etc.
What I've just described is basically the model portion of an MVC-style application. The other two parts would be controllers which call the service methods, and views which output data retrieved from service methods. This approach keeps responsibilities separate and isolated and allows you to put higher-level logic and functionality together like building blocks. Business objects are the lowest building block, their structure needs to be solid and well defined for the rest to work. Data-object mappers just concern themselves with putting those objects into the database and getting them back out again. Services then put all this together in various complex ways and make things happen.
You shouldn't have any cyclic dependencies with this, as responsibilities are well separated. Your individual dependencies may still be somewhat complex. If it becomes too cumbersome to instantiate classes, you'll want to look into Factories:
$factory = new Factory;
$userStorage = $factory->newUserStorage();
All the complexity of instantiation is encapsulated in this factory. One step further are dependency injection containers, who you can configure in, for example, an XML file to specify which class depends on what, and then the DI container will take care of it for you.
I was thinking about website programming in PHP and how easier it was
before the OOP
Well, stick to procedural then. If it is easier to write a well written website in a procedural or functional way then opposed to the ojbect-oriented way. Stick ti what you are used to. OO isn't better then functional. It's just a different approach.
the public void main() in php
In the lanuage Java every piece of software we write has a single entry point. The public void main() method. This method fires up the entire application and passes in the arguments provided on startup. It is also the only exit point in the application. the application ends in this method (unless it crashes).
In php, there is no single entry point. We have a bunch of files that run some scripts that do some more stuff and then somewhere along the line another script decides to return stuff and die();
Dependency injection and how IoC libraries can help
When using dependency injection, it becomes a real pain in the a$$ when creating objects and passing arround the correct instance of a class. We start solving this problem with ugly solutions: Singleton, globals, statics, ... Making our software more and more tightly coupled and harder to maintain.
Inversion of Control can help here. there are some really greate articles on the webz.
You can use autoloading in PHP for a better solution:
http://php.net/manual/en/language.oop5.autoload.php
Does the below code show an acceptable way to cache both fully built pages and database queries?
The caching of built pages is started with the __construct in the controller and then finished with the __destruct, in this example all pages are cached for a default of 15 minutes to a file.
The query caching is done with apc and they are stored in memory for the specified amount of time per query. In the actual site there would be another class for the apc cache so that it could be changed if required.
My aim was to build the most simple possible mvc, have I failed or am I on the right sort of track?
Controller
//config
//autoloader
//initialiser -
class controller {
var $cacheUrl;
function __construct(){
$cacheBuiltPage = new cache();
$this->cacheUrl = $cacheBuiltPage->startFullCache();
}
function __destruct(){
$cacheBuiltPage = new cache();
$cacheBuiltPage->endFullCache($this->cacheUrl);
}
}
class forumcontroller extends controller{
function buildForumThread(){
$threadOb = new thread();
$threadTitle = $threadOb->getTitle($data['id']);
require 'thread.php';
}
}
Model
class thread extends model{
public function getTitle($threadId){
$core = Connect::getInstance();
$data = $core->dbh->selectQuery("SELECT title FROM table WHERE id = 1");
return $data;
}
}
Database
class database {
public $dbh;
private static $dsn = "mysql:host=localhost;dbname=";
private static $user = "";
private static $pass = '';
private static $instance;
private function __construct () {
$this->dbh = new PDO(self::$dsn, self::$user, self::$pass);
}
public static function getInstance(){
if(!isset(self::$instance)){
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
public function selectQuery($sql, $time = 0) {
$key = md5('query'.$sql);
if(($data = apc_fetch($key)) === false) {
$stmt = $this->dbh->query($sql);
$data = $stmt->fetchAll();
apc_store($key, $data, $time);
}
return $data;
}
}
Cache
class cache{
var url;
public function startFullCache(){
$this->url = 'cache/'.md5($_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
if((#filesize($this->url) > 1) && (time() - filectime($this->url)) < (60 * 15)){
readfile($this->url);
exit;
}
ob_start();
return $this->url;
}
public function endFullCache($cacheUrl){
$output = ob_get_contents();
ob_end_clean();
$output = sanitize_output($output);
file_put_contents($cacheUrl, $output);
echo $output;
flush();
}
}
View
<html>
<head>
<title><?=$threadTitle[0]?> Thread - Website</title>
</head>
<body>
<h1><?=$threadTitle[0]?> Thread</h1>
</body>
</html>
"Outsource" the caching
First of all, you have to understand that caching of GET request is usually done all over the internet. Especially if your user is connecting via some kind of proxy.
And then there is also ability to set long expire time, so that user's browser does the caching of the HTML page and/or the media files.
For starting to look into this, you should read these two articles.
What is your goal?
Before you begin attempting to add cache, make sure that you actually need it. Do some benchmarking and look into what are your bottlenecks. Optimization for sake of optimizing is pointless and often harmful.
If you KNOW (and have data to back it up .. it's not about "feeling") that your application is making too many SQL queries, instead of jumping to query caching, you should begin by examining, what are those queries for.
For example:If you see, that you are performing slow query each page-view just to generate a tag cloud, you instead should store the already completed tag cloud (as HTML fragment) and update it only, when something has changed.
Also, "add cache" should never be your first step, when trying to improve performance. If your queries are slow, use EXPLAIN to see if they are using indexes properly. Make sure that you are not querying same data multiple times. And also see, if queries actually make sense.
This is not MVC
I am not sure, where did you learn to write this way, but you seem to be missing the whole point of MVC:
"view" is not a template
"model" is not a database abstraction
"controller" is not application logic
You also seem to be missing the meaning for the word "layer". It is NOT a synonym for "class". Layers are groups of reusable components that are reusable in similar circumstances [1].
You might benefit from reading this and this post. They should help you understand the basic of this architectural pattern.
Where to cache in MVC architecture?
There are basically two points at which you can do the caching, when working with MVC (or MVC-inspired) architecture: views and persistence logic.
Caching for views would mostly entail reuse of once rendered templates (each view in MVC would be juggling multiple templates and associated UI logic). See the example with tag cloud earlier.
The caching in persistence logic would depend on your implementation.
You can cache the data, that is supposed to be passed to the domain objects, withing services:
Note: in real application the new instances would not be here. Instead you would be using some factories
$user = new User;
$user->setId( 42 );
$cache = new Cache;
if ( !$cache->fetch( $user ))
{
$mapper = new UserMappper;
$mapper->fetch( $user );
}
$user->setStatus( User::STATUS_BANNED );
$cache->store( $user );
$mapper->store( $user );
// User instance has been populated with data
The other point for cache would be Repositories and/or Identity maps, if you expand the persistence layer beyond use of simple mapper. That would be too hard explain in with a simple code example. Instead you should read Patterns of Enterprise Application Architecture book.
.. some other bad practices in your code:
Please stop using singletons for establishing DB connection. It makes impossible to write unit tests and causes tight coupling to specific name of a class. I would recommend to instead use this approach and inject the DB connection in classes, that require it.
Also, if your query has no parameters, there is no point in preparing it. Prepared statement are for passing data to SQL .. but none of your example has any parameters.
This issue arises mostly because of your magical Database class. Instead you should separate the persistence logic in multiple data mappers. This way you would not be face with self-inflicted problem of having single method for all queries.
The var keyword is an artifact of PHP4. Nowadays we use public, private and protected.
You are hard coding the connection details in your code. It is basically a violation of OCP (the dumbed-down version: here).
Update
Is this an acceptable way to cache both queries and built pages in a PHP mvc?
The caching of built pages is started with the __construct in the controller and then finished with the __destruct, in this example all pages are cached for a default of 15 minutes to a file.
The destructor will be called when the all references are freed, or when the script terminates. I assume this means when the script terminates properly. I would say that critical exceptions would not guarantee the destructor to be called.
for example
class A
{
public function __construct()
{
echo "Construct\n";
}
public function __destruct()
{
echo "Destruct\n";
}
}
test code:
$test = new A();
die( "Dead\n"); // Will output Construct; dead; Destruct
$test = new A();
throw new Exception("Blah\n"); // Construct, Fatal error (no destruct)
$test = new A();
require_once( 'invalid_file.php'); // Construct, Fatal error (no destruct)
You'd better use register_shutdown_function() to go for sure. but be careful
Multiple calls to register_shutdown_function() can be made, and each will be called in the same order as they were registered. If you call exit() within one registered shutdown function, processing will stop completely and no other registered shutdown functions will be called." There's no guarantee that your shutdown function will be called if some other shutdown function runs before yours.
IMHO, you are reinventing the wheels there is a lot of frameworks already. do you want a simple and small one ? well there is Silex
which is built from the same guy who created Symfony. trust me you will waste your time.
or why not try using Laravel you can choose only the packages you want not all the framework
they already have a well designed caching system see http://laravel.com/docs/cache
To understand how caching is done right in MVC style Symfony 2's documentation has a very good explanation
Also read this question Caching strategies in MVC Framework
In terms of how necessary any of this is; it really depends on your situation. In my experience, unless you're expecting large numbers of users (say, more than a few dozen on your site at the same time), you don't need caching. A site like StackOverflow, on the other hand, would not be able to function without a very well thought out caching strategy.
How would you create a build function to cache the entire built page?
as i understood from your question you want to cache the entire page ?
How would you create a build function to cache the entire built page?
you can simply use output buffering to achieve this.
an example is that you have index.php code:
<?php
ob_start();
// All your mvc and application logic here
$output = ob_get_contents();
ob_end_clean();
the entire page output between ob_start() and ob_get_contents() is now captured in $output
you can save it in a file and do what ever you want
you can read more about ob_get_contents() in PHP Website
It all depends on where your performance problems lie. If they are within your DB queries, then cache those - but of course your controller needs to be prepared for dirty data.
If you were to cache stuff at the controller layer, then that will perform better, but you'll probably have more stuff to cache (your DB data is going to be smaller than your HTML). Then of course the user will need to be prepared for seeing dirty data.
Unfortunately you can't really have any hard and fast rules because each solution has different requirements. My advice is to only start caching data when you really need to. Have a close look at where your performance bottlenecks are and do your caching appropriately, and make sure you can scale outwards (more machines) not just upwards (increasing spec of machine).
I add to what CodingInsane have posted!
He is right this way you can easily make your own little cache Mechanism.
just write the content of $output (in the CodingInsane post) to a file like: the_file.php.cache
and next time in the the_file.php read the content of the_file.php.cache and display it the user and exit.
However any cache mechanism needs a way to update (rebuild the page). To do so you just have to keep track if the content has changed or check the last time the content has changed and compare it with the last time the the_file.php.cache has been modified filemtime().
Good Luck!
My code is located here: https://github.com/maniator/SmallFry
Should I make it so that that the App class does not have to use static functions but at the same time be able to set and set variables for the app from anywhere?
Or should I keep it how it is now with App::get and App::set methods?
What are the advantages and disadvantages of both?
How would I accomplish that 1st task if I was to undertake it?
Related Question
Sample code:
//DEFAULT TEMPLATE
App::set('APP_NAME', 'SmallVC');
//END DEFAULT TEMPLAT
//
//DEFAULT TEMPLATE
App::set('DEFAULT_TEMPLATE', 'default');
//END DEFAULT TEMPLATE
//DEFAULT TITLE
App::set('DEFAULT_TITLE', 'Small-VC');
//END DEFAULT TITLE
//LOGIN SEED
App::set('LOGIN_SEED', "lijfg98u5;jfd7hyf");
//END LOGIN SEED
App::set('DEFAULT_CONTROLLER', 'AppController');
if(App::get('view')){
$template_file = $cwd.'/../view/'.App::get('view').'/'.App::get('method').'.stp';
if(is_file($template_file)){
include $template_file;
}
else {
include $cwd.'/../view/missingview.stp'; //no such view error
}
}
else {
App::set('template', 'blank');
include $cwd.'/../view/missingfunction.stp'; //no such function error
}
I think you have a feeling that static is bad. What I am posting may seem fairly crazy as it is a massive change. At the very least hopefully it presents a different idea of the world.
Miško Hevery wrote static methods are a death to testability.
I like testing, so for that reason I don't use them. So, how else can we solve the problem? I like to solve it using what I think is a type of dependency injection. Martin Fowler has a good but complicated article on it here.
For each object at construction I pass the objects that are required for them to operate. From your code I would make AppController become:
class AppController
{
protected $setup;
public function __construct(array $setup = array())
{
$setup += array('App' => NULL, 'Database' => NULL);
if (!$setup['App'] instanceof App)
{
if (NULL !== $setup['App'])
{
throw new InvalidArgumentException('Not an App.');
}
$setup['App'] = new App();
}
// Same for Database.
// Avoid doing any more in the constructor if possible.
$this->setup = $setup;
}
public function otherFunction()
{
echo $this->setup['App']->get('view');
}
}
The dependancies default to values that are most likely (your default constructions in the if statements). So, normally you don't need to pass a setup. However, when you are testing or want different functionality you can pass in mocks or different classes (that derive from the right base class). You can use interfaces as an option too.
Edit The more pure form of dependency injection involves further change. It requires that you pass always pass required objects rather than letting the class default one when the object isn't passed. I have been through a similar change in my codebase of +20K LOC. Having implemented it, I see many benefits to going the whole way. Objects encapsulation is greatly improved. It makes you feel like you have real objects rather than every bit of code relying on something else.
Throwing exceptions when you don't inject all of the dependencies causes you to fix things quickly. With a good system wide exception handler set with set_exception_handler in some bootstrap code you will easily see your exceptions and can fix each one quickly. The code then becomes simpler in the AppController with the check in the constructor becoming:
if (!$setup['App'] instanceof App)
{
throw new InvalidArgumentException('Not an App.');
}
With every class you then write all objects would be constructed upon initialisation. Also, with each construction of an object you would pass down the dependencies that are required (or let the default ones you provide) be instantiated. (You will notice when you forget to do this because you will have to rewrite your code to take out dependencies before you can test it.)
It seems like a lot of work, but the classes reflect the real world closer and testing becomes a breeze. You can also see the dependencies you have in your code easily in the constructor.
Well, if it was me, I would have the end goal of injecting the App dependency into any class (or class tree) that needs it. That way in testing or reusing the code you can inject whatever you want.
Note I said reuse there. That's because it's hard to re-use code that has static calls in it. That's because it's tied to the global state so you can't really "change" the state for a subrequest (or whatever you want to do).
Now, on to the question at hand. It appears that you have a legacy codebase, which will complicate things. The way I would approach it is as follows:
Create a non-static version of the app class (name it something different for now) that does nothing but proxy its get/set calls to the real app class. So, for example:
class AppProxy {
public function set($value) {
return App::set($value);
}
}
For now, all it has to do is proxy. Once we finish getting all the code talking to the proxy instead of the static app, we'll make it actually function. But until then, this will keep the application running. That way you can take your time implementing these steps and don't need to do it all in one big sweep.
Pick a main class (one that does a lot for the application, or is important) that you easily control the instantiation of. Preferably one that you instantiate in only one place (in the bootstrap is the easiest). Change that class to use Dependency Injection via the constructor to get the "appproxy".
a. Test this!
Pick another class tree to work on, based on what you think will be most important and easiest.
a. Test!!!
If you have more calls to App::, Go to #3
Change the existing App class to be non-static.
a. Test!!!!!!!!!!
Remove the AppProxy and replace with App in the dependency injectors. If you did it right, you should only have one place to change to make this switch.
Pat yourself on the back and go get a drink, cause you're done.
The reason that I segmented it out like this is that once a step is completed (any step), you can still ship working software. So this conversion could take literally months (depending on the size of your codebase) without interrupting business as usual...
Now, once you're done, you do get some significant benefits:
Easy to test since you can just create a new App object to inject (or mock it as needed).
Side effects are easier to see since the App object is required wherever it could be changed.
It's easier to componentize libraries this way since their side effects are localized/
It's easier to override (polymorphism) the core app class if it's injected than if it's static.
I could go on, but I think it's pretty easy to find resources on why statics are generally bad. So that's the approach I would use to migrate away from a static class to an instance...
If you don't want to have static functions but global access from everywhere WITHOUT passing the object to the places where it is actually needed then you pretty much can only use one thing:
A global variable
So you are not really better of doing that. But that is the only thing i can think of that would fulfill your requirements.
If you App object is something like an application config a first possible step would be to pass it to the objects that need it:
class Login {
public function __construct() {
$this->_login_seed = App::get('LOGIN_SEED');
self::$_ms = Database::getConnection();
}
changes into:
class Login {
public function __construct(App $app) {
$this->_login_seed = $app->get('LOGIN_SEED');
self::$_ms = Database::getConnection();
}
Writing a PHP app and have several classes that only have static methods (no need for instance methods). An example of one is NumericValidator, which has methods like checkInteger($toCheck) which checks to make sure the argument you pass it is of type int, and checkGreaterThan($lOperand, $rOperand), which makes sure that the left operand is greater than the right operand, etc.
I know I could just throw each of these methods into a PHP file without putting them inside of a class, but I want to take an OOP approach here in case the API evolves to require instantiating NumericValidator.
But it does beg the question: how is a class with 100% static methods any different than have a class implement a singleton design pattern, where every reference used throughout the code base invokes the same instance?
For example, here is what my code looks like now:
public function doSomething($p_iNum)
{
if(!NumericValidator::checkInteger($p_iNum))
// throw IllegalArgumentException
// ...
}
But I could turn all of NumericValidator's static methods into non-static instance methods, forcing the programmer to instantiate it, and then implement a singleton design pattern so you can only ever reference 1 instance of it:
public function doSomething($p_iNum)
{
NumericValidator $nv = NumericValidator::getInstance();
if(!nv->checkInteger($p_iNum))
// throw IllegalArgumentException
// ...
}
Finally, my question: which is better and more in keeping with best practices? Are there performance considerations? How would either approach affect things like concurrency, or requests coming from multiple users?
I would use a static class in your example. The differentiator I would use is if there is any state of the properties of an instance you are trying to preserve across access. This is what a singleton is designed for. The static class gives organized access to methods in a namespace which is helpful for clarity in your code but it does not have any properties about itself.
So yes you can use a singleton but it would be bad form because there are no instance properties that you want to make available across page accesses.
Hope this helps.
Use Singleton instead of static class only if you going to pass instance of NumericValidator in variable to some function.
In PHP 5.3 you can get instance of static class:
class test
{
public static function instance()
{
print 'zz';
}
}
$z = new test;
$z->instance();
Don't care about concurrency requests in PHP, it's single threaded, each process executes own code.