I have a problem in optimizing my PHP script. For example:
A MySQL Table:
option_name || option_value
=====================================================
base_url || http://mysite.com/myproject
theme_name || default
language || en
MyScript.php file:
class options {
private $options = null;
public function get($optionName) {
if(!isset($this->options))
self::get_data();
return $this->options[$optionName];
}
protected function get_Data() {
// ...
// DO A MYSQL QUERY AND SAVE IT TO $this->options
// ...
}
}
The data which this class returns is constant. So there is no need to run a MySQL query every time I need to access for example base_url value. What is the best way to create an object and use it global?
$OPTIONS = new options;
function load_option($optName) {
global $OPTIONS;
return $OPTIONS->get($optName);
}
Something like this function maybe? Someone told this is The Worst Possible Way.
I need help. Thanks!
Your problem here, is that you do not understand what SOLID and DI principles are. You should implement classes that serve each singular responsibility, then inject their instances on demand.
In your case, it would look like this,
class Config
{
protected $pdo;
protected $cache;
public function __construct($pdo)
{
$this->pdo = $pdo;
}
public function read($key)
{
// Read a value by its key from a table
// Here should be a SELECT query
// You can also prevent reading the same thing twice
// by storing it in a cache
}
public function write(array $data)
{
foreach ($data as $key => $value) {
// Here should be INSERT statement
}
}
public function delete($key)
{
// Here comes a DELETE statement
}
}
Each time you need to read a configuration value, you would simply inject an instance of Config to a class that needs it.
class Foo
{
protected $config;
public function __construct(Config $config)
{
$this->config = $config;
}
public function doSomethingDependingOnConfig()
{
if ($this->config->read('lang') === 'en') {
// do something
}
}
}
And you would use it like,
$pdo = new PDO(...);
$config = new Config($pdo);
// Test
echo $config->read('lang'); //en
// So,
$foo = new Foo($config);
$foo->doSomethingDependingOnConfig();
Actually, I don't think that's the worst possible way.
Many config settings don't need to be stored in a database. Some even can't be (like the address and credentials of the database).
So is it obvious that some hard coded config is convenient. And if you would investigate existing PHP applications, you'll see that most of them will have some globally configurable options.
The disadvantage of a global variable, is that its very strict and hard to change it's usage. Soon you'll find yourself using this global thoughout your application.
But you already countered that by wrapping access to it in a function, so you can easily change the options later, without having to change your entire application. You've hidden the way the options are stored by making this wrapper function. If you'd like, you could still fetch them from the database, or start storing them in a file, because all you need to change is this function. So this is quite a good solution, actually.
One thing you could do to improve this code:
Maybe you could wrap it in a Config singleton class. The advantage of that, is that you can actually store the config in that class as well, getting rid of the global variable, and therefor, getting rid of accidental access to that global. You will force yourself to always use the function/class access to the options.
Related
A couple of the options are:
$connection = {my db connection/object};
function PassedIn($connection) { ... }
function PassedByReference(&$connection) { ... }
function UsingGlobal() {
global $connection;
...
}
So, passed in, passed by reference, or using global. I'm thinking in functions that are only used within 1 project that will only have 1 database connection. If there are multiple connections, the definitely passed in or passed by reference.
I'm thining passed by reference is not needed when you are in PHP5 using an object, so then passed in or using global are the 2 possibilities.
The reason I'm asking is because I'm getting tired of always putting in $connection into my function parameters.
I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:
class ResourceManager {
private static $DB;
private static $Config;
public static function get($resource, $options = false) {
if (property_exists('ResourceManager', $resource)) {
if (empty(self::$$resource)) {
self::_init_resource($resource, $options);
}
if (!empty(self::$$resource)) {
return self::$$resource;
}
}
return null;
}
private static function _init_resource($resource, $options = null) {
if ($resource == 'DB') {
$dsn = 'mysql:host=localhost';
$username = 'my_username';
$password = 'p4ssw0rd';
try {
self::$DB = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
} elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
self::$$resource = new $resource($options);
}
}
}
And then in functions / objects / where ever:
function doDBThingy() {
$db = ResourceManager::get('DB');
if ($db) {
$stmt = $db->prepare('SELECT * FROM `table`');
etc...
}
}
I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.
Try designing your code in an object-oriented fashion. Methods that use the database should be grouped in a class, and the class instance should contain the database connection as a class variable. That way the database connection is available to the functions that need it, but it's not global.
class MyClass {
protected $_db;
public function __construct($db)
{
$this->_db = $db;
}
public function doSomething()
{
$this->_db->query(...);
}
}
I see that a lot of people have suggested some kind of static variable.
Essentially, there is very little difference between a global variable and a static variable. Except for the syntax, they have exactly the same characteristics. As such, you are gaining nothing at all, by replacing a global variable with a static variable. In most examples, there is a level of decoupling in that the static variable isn't referred directly, but rather through a static method (Eg. a singleton or static registry). While slightly better, this still has the problems of a global scope. If you ever need to use more than one database connection in your application, you're screwed. If you ever want to know which parts of your code has side-effects, you need to manually inspect the implementation. That's not stuff that will make or break your application, but it will make it harder to maintain.
I propose that you chose between one of:
Pass the instance as arguments to the functions that needs it. This is by far the simplest, and it has all the benefits of narrow scope, but it can get rather unwieldy. It is also a source for introducing dependencies, since some parts of your code may end up becoming a middleman. If that happens, go on to ..
Put the instance in the scope of the object, which has the method that needs it. Eg. if the method Foo->doStuff() needs a database connection, pass it in Foo's constructor and set it as a protected instance variable on Foo. You can still end up with some of the problems of passing in the method, but it's generally less of a problem with unwieldy constructors, than with methods. If your application gets big enough, you can use a dependency injection container to automate this.
My advice is to avoid global in the bulk of the code - it's dangerous, hard to track and will bite you.
The way that I'd do this is to have a function called getDB() which can either be at class level by way of a constructor injection or static within a common class.
So the code becomes
class SomeClass {
protected $dbc;
public function __construct($db) {
$this->dbc = $db;
}
public function getDB() {
return $this->dbc;
}
function read_something() {
$db = getDB();
$db->query();
}
}
or using a common shared class.
function read_something() {
$db = System::getDB();
$db->query();
}
No matter how much elegant system design you do, there are always a few items that are necessarily global in scope (such as DB, Session, Config), and I prefer to keep these as static methods in my System class.
Having each class require a connection via the constructor is the best way of doing this, by best I mean most reliable and isolated.
However be aware that using a common shared class to do this can impact on the ability to isolate fully the objects using it and also the ability to perform unit tests on these objects.
None of the above.
All the mysql functions take the database connection argument optionally. If you leave that argument out, the last connection by mysql_connect() is assumed.
function usingFunc() {
$connection = getConnection();
...
}
function getConnection() {
static $connectionObject = null;
if ($connectionObject == null) {
$connectionObject = connectFoo("whatever","connection","method","you","choose");
}
return $connectionObject;
}
This way, the static $connectionObject is preserved between getConnection calls.
One of my colleagues moved to a different company and I got his source code of an existing project.
I was shocked how messy the code looked. I am not a PHP developer so maybe this is a stupid question but it seems to me that he uses the $_SESSION too much and we get many errors regarding the Sessions. I was wondering if it would be good to encapsulate the $_SESSION and write for each value he uses an own method.
The problem I see with this code is that he uses the session object like this
$_SESSION['customer']['items'] = getItems() //returns an array
$_SESSION['article'][$Id]['name'] = utf8_decode[$received[1]];
So from my point of view I would store all his stuff in simple Popos and place those into the Session.
So the Popo for the customer would look like this
class CustomerPopo
{
private $_id;
private $_salutation;
private $_name;
private $_surename;
public function getId()
{
return $this->_id;
}
public function setId($value)
{
$this->_id = $value;
}
public function getSalutation()
{
return $this->_salutation;
}
public function setSalutation($value)
{
$this->_salutation = $value;
}
public function getName()
{
return $this->_name;
}
public function setName($value)
{
$this->_name = $value;
}
public function getSurename()
{
return $this->_surename;
}
public function setSurename($value)
{
$this->_surename = $value;
}
function CustomerPopo() {
}
}
And I imagined the SessionManager like this
class SessionManager
{
private static function getValue($valueName)
{
$value = SessionManager::getValueFromSession($valueName);
if (is_null($value)) {
//Handle stuff and do further checks
}
return $value;
}
private static function getValueFromSession($valueName)
{
$value = null;
if (isset($_SESSION[$valueName])) {
$value = $_SESSION[$valueName];
}
return $value;
}
private static function setValue($valueName, $value)
{
$_SESSION[$valueName] = $value;
}
private static function clearValue($valueName)
{
if (isset($_SESSION[$valueName])) {
unset($_SESSION[$valueName]);
}
}
public static function getCustomer()
{
$customer = '';
try {
$customer = SessionManager::getValue('customer');
} catch (Exception $e) {
$customer = '';
}
return $customer;
}
public static function setCustomer($customer)
{
SessionManager::setValue('customer', $customer);
}
}
With this I could kill some of the errors which arise from different spellings of the word customer/Customer/cusomter.
I imagine the SessionManager would grow big because we have ~30 Session variables in the code.
Is there a design pattern which I could follow to implement such a SessionManager without making it worse in the end ? as stated I am not very familiar with PHP (yet).
EDIT:
Since the approach seems to be valid how can I handle the 30 Session variables i mentioned ? If I have a set/get and maybe a clear method for each value i will end up with 60-90 methods
It is a good idea to have an object encapsulating the access to global variables such as $_SERVER, $_GET, $_POST or $_SESSION as in your example. It is common practice in MVC architecture to do so.
Should the class have methods for IDE completition? That is actually up to you, but common practice at workplaces where I worked was not to have them but make const string identifiers of the fields instead, which are then used to specifying the index in the global $_SESSION variable through an object, such as your SessionManager.
But even then, I would probably ditch the static methods and go with an instance of the manager instead. Having a class with static methods may prevent typos, but does not fix the global state issue, which can be a huge problem when unit testing your applicaion.
I absolutely agree that using the $_SESSION like your college did is messy, since you have a hard time to figure out what is actually stored in the session.
In my opinion, the CustomerPopo is a very good idea, since it is very easy to understand the available data. Also, an IDE will be able to understand it either and offer this information to you as code completion and checks.
I also like your SessionManager, but I would try to get rid of these getValue/setValue functions and move to move verbose functions like getCustomer/setCustomer.
I guess you are not using a PHP framework. I think you should have a look at them, they are very handy (for instance Symfony or Yii2).
One last thing: Always keep in mind that all data stored in the session object will be loaded and parsed for each request, nevertheless if you use it or not. So if you store a lot of data which you only just for specific request, you should consider using another place to store it, like an external cache.
Also, the Session introduces state, which you should avoid if any possible.
Let's say I have something like this:
<?php
namespace Twitter;
class Twitter {
function __construct()
{
$config = array ('api' => 'something', 'api_url' => 'something2');
}
// some code goes here
}
class TwitterConnection {
function __construct()
{
$config = array ('api' => 'something', 'api_url' => 'something2');
}
// some code goes here
}
?>
and so on - there will be more classes that uses $config variables.
Now, the question is: how can I define config only once, and make it accessible across all classes?
Thanks
You could create a configuration object that reads from your data source (ini, db, php file ...) and populates itself. Then give it a getter so you can get the configuration properties stored within.
Something along the lines of Config::get('someProperty')
Once you have this object setup, you can pass it to the constructor of your classes so it can be used in inside.
class Twitter {
function __construct($config) {
$state = $config->get('someState');
}
}
You could also simply use it within your classes without injecting it by making it a static class (You could also just as easily create a new instance).
class Twitter {
function __construct() {
//Don't recommend this, better to inject it.
$state = Config::get('someState');
}
}
EDIT
The simplest config class that uses your hardcoded array would look something like this. Again, I suggest you move out your configuration out of your code.
class Config {
private $opts = array();
public function __construct() {
/**
* Ideally opts should be coming from some kind of easy to
* access configuration file
*
*/
$this->opts = array ('api' => 'something', 'api_url' => 'something2');
}
public function get($key) {
if (isset($this->opts[$key])) {
return $this->opts[$key];
}
return false;
}
}
class Twitter {
function __construct($config) {
echo $config->get('api');
}
}
$config = new Config();
new Twitter($config);
You could also change the class a bit so that it works without needing an instance of itself.
There are a couple of different things in play here - config data storage, and config data representation and use.
For storage, as martswite commented above, you could have a config file. You could also have config data stored in a database.
For data representation, you could have an array, like you've shown in your question, or a separate full-fledged object.
Usually, if you have objects that have a dependency on certain data in order to work, you pass (inject) that dependency into the object through its constructor. So, roughly, something like this:
class Example
{
private $dependency;
public function __construct($dependency)
{
$this->dependency = $dependency;
}
public function doSomething()
{
// do something with $this->dependency
}
}
This would be tedious to do manually if you had many objects which required the same dependency. Thankfully, there are dependency injection containers which automate a lot of the process. Where do you find these containers? A Google search should yield results. That said, Symfony seems like a popular option: http://components.symfony-project.org/dependency-injection/
All that said, there's a bit of a learning curve to understanding and using a DI container. Still, it's probably the best way to go without introducing globals into your code.
Finally, just to give you an idea of how to use it, here's some pseudo-code:
// Load config data from file/db/some other source. Use it to populate an object (most likely) or array
// Set up the DI container to automatically inject the config data into the objects which require it
// Profit
Try:
namespace Twitter;
$config = array ('api' => 'something', 'api_url' => 'something2');
class Twitter {
function __construct()
{
global $config;
}
}
class TwitterConnection {
function __construct()
{
global $config;
}
}
?>
For the sake of simplicity, assume I have 2 classes, User and UserStatus, used in a Web application.
<?php
// library code:
class UserStatus {
protected $_status = NULL;
private function fetchDataFromDB() {
// regular DB stuff
$this->_status = ...
// result will be something like 'online', 'away', etc.
}
public function getIcon() {
global $icon_array;
if (is_null($this->_status)) {
$this->fetchDataFromDB()
}
return $icon_array[$this->_status];
}
}
class User {
protected $user_id;
public $user_name;
protected $status;
public function __construct() {}
public static function getAll() {
// some DB stuff
return $users;
}
}
// and now, in index.php:
$users = User::getAll();
// echoes the icon to use to reflect the current user status
foreach ($users as $user) {
echo <img src="$user->status->getIcon()"/>;
}
?>
In most of the HTTP request the status object will not be used so I'm looking for a way to only instantiate it as needed (call it lazy loading). How should I intercept the status->method() call and create that object on-the-fly?
An important note is that I need $user_id available in the UserStatus class, otherwise the fetchDataFromDB() method won't know to which user it should fetch the data. How should this be done?
I've looked at some interesting stuff on this matter like Fabien Potencier's What is Dependency Injection? and Pimple - a PHP 5.3 dependency injection container and also some articles about the Proxy Pattern but to implement them it looks like I have to mess a lot with the current code. Is there a simpler way?
Maybe im missing something but it seems the easiest solution in this instance would be to have your getter for Status simply create the object if it doesnt exist...
public function getStatus()
{
if(!isset($this->status))
{
// or however you creat this object..
$this->status = new UserStatus($this->user_id);
}
return $this->status;
}
public function __get($property)
{
$method = 'get'.ucfirst($property); // getStatus
if(method_exists($this, $method))
{
return $this->$method();
}
}
By using the __get magic method anytime you do $user->status it will call $user->getStatus(). Ofcourse you could also always just access it like: $user->getStatus()->getIcon() as well.
However you decide to set up accessing your properties i would recommend doing it in a consistent way across your entire model.
You could put the status class in a different file and then leverage php's autoloading mechnism:
http://php.net/manual/de/language.oop5.autoload.php
to not load that file until you access it.
There are rumors that auto loading (or actually just any kind of conditional loading) is troublesome for byte code caches and optimizers though unfortunately I don't know too much about the impact.
P.S.: The manual does not say rhis explicity at this point: You can also use spl_autoload_register() instead of just defining the magic __autoload function. This is slightly more powerful.
A couple of the options are:
$connection = {my db connection/object};
function PassedIn($connection) { ... }
function PassedByReference(&$connection) { ... }
function UsingGlobal() {
global $connection;
...
}
So, passed in, passed by reference, or using global. I'm thinking in functions that are only used within 1 project that will only have 1 database connection. If there are multiple connections, the definitely passed in or passed by reference.
I'm thining passed by reference is not needed when you are in PHP5 using an object, so then passed in or using global are the 2 possibilities.
The reason I'm asking is because I'm getting tired of always putting in $connection into my function parameters.
I use a Singleton ResourceManager class to handle stuff like DB connections and config settings through a whole app:
class ResourceManager {
private static $DB;
private static $Config;
public static function get($resource, $options = false) {
if (property_exists('ResourceManager', $resource)) {
if (empty(self::$$resource)) {
self::_init_resource($resource, $options);
}
if (!empty(self::$$resource)) {
return self::$$resource;
}
}
return null;
}
private static function _init_resource($resource, $options = null) {
if ($resource == 'DB') {
$dsn = 'mysql:host=localhost';
$username = 'my_username';
$password = 'p4ssw0rd';
try {
self::$DB = new PDO($dsn, $username, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
} elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
self::$$resource = new $resource($options);
}
}
}
And then in functions / objects / where ever:
function doDBThingy() {
$db = ResourceManager::get('DB');
if ($db) {
$stmt = $db->prepare('SELECT * FROM `table`');
etc...
}
}
I use it to store messages, error messages and warnings, as well as global variables. There's an interesting question here on when to actually use this type of class.
Try designing your code in an object-oriented fashion. Methods that use the database should be grouped in a class, and the class instance should contain the database connection as a class variable. That way the database connection is available to the functions that need it, but it's not global.
class MyClass {
protected $_db;
public function __construct($db)
{
$this->_db = $db;
}
public function doSomething()
{
$this->_db->query(...);
}
}
I see that a lot of people have suggested some kind of static variable.
Essentially, there is very little difference between a global variable and a static variable. Except for the syntax, they have exactly the same characteristics. As such, you are gaining nothing at all, by replacing a global variable with a static variable. In most examples, there is a level of decoupling in that the static variable isn't referred directly, but rather through a static method (Eg. a singleton or static registry). While slightly better, this still has the problems of a global scope. If you ever need to use more than one database connection in your application, you're screwed. If you ever want to know which parts of your code has side-effects, you need to manually inspect the implementation. That's not stuff that will make or break your application, but it will make it harder to maintain.
I propose that you chose between one of:
Pass the instance as arguments to the functions that needs it. This is by far the simplest, and it has all the benefits of narrow scope, but it can get rather unwieldy. It is also a source for introducing dependencies, since some parts of your code may end up becoming a middleman. If that happens, go on to ..
Put the instance in the scope of the object, which has the method that needs it. Eg. if the method Foo->doStuff() needs a database connection, pass it in Foo's constructor and set it as a protected instance variable on Foo. You can still end up with some of the problems of passing in the method, but it's generally less of a problem with unwieldy constructors, than with methods. If your application gets big enough, you can use a dependency injection container to automate this.
My advice is to avoid global in the bulk of the code - it's dangerous, hard to track and will bite you.
The way that I'd do this is to have a function called getDB() which can either be at class level by way of a constructor injection or static within a common class.
So the code becomes
class SomeClass {
protected $dbc;
public function __construct($db) {
$this->dbc = $db;
}
public function getDB() {
return $this->dbc;
}
function read_something() {
$db = getDB();
$db->query();
}
}
or using a common shared class.
function read_something() {
$db = System::getDB();
$db->query();
}
No matter how much elegant system design you do, there are always a few items that are necessarily global in scope (such as DB, Session, Config), and I prefer to keep these as static methods in my System class.
Having each class require a connection via the constructor is the best way of doing this, by best I mean most reliable and isolated.
However be aware that using a common shared class to do this can impact on the ability to isolate fully the objects using it and also the ability to perform unit tests on these objects.
None of the above.
All the mysql functions take the database connection argument optionally. If you leave that argument out, the last connection by mysql_connect() is assumed.
function usingFunc() {
$connection = getConnection();
...
}
function getConnection() {
static $connectionObject = null;
if ($connectionObject == null) {
$connectionObject = connectFoo("whatever","connection","method","you","choose");
}
return $connectionObject;
}
This way, the static $connectionObject is preserved between getConnection calls.