What is the best way to create a Singleton Webservice in PHP? - php

We have a need to access a DB that only allows one connection at a time. This screams "singleton" to me. The catch of course is that the singleton connection will be exposed (either directly or indirectly) via a web-service (most probable a SOAP based web-service - located on a separate server from the calling app(s) ) - which means that there may be more than one app / instance attempting to connect to the singleton class.
In PHP, what is the best way to create a global singleton or a web-service singleton?
TIA

This screams "use a DB SERVER" to me. ;-), but...
You could create an SoapServer and use a semaphore to allow only 1 connection at a time
$s1 = sem_get(123, 1);
sem_acquire($s1);
// soapserver code here
sem_release($s1);

In PHP, there is no such thing as a "global" object that resides across all requests . In a java webserver, this would be called "application level data store". In php, the extent of the "global" scope (using the global keyword) is a single request. Now, there is also a cross session data store accessible via $_SESSION, but I'm trying to highlight that no variable in php is truly "global". Individual values emulate being global by being stored to a local file, or to a database, but for something like a resource, you are stuck creating it on each request.
Now, at the request level, you can create a Singleton that will return an initialized resource no matter which scope within the request you call it from, but again, that resource will not persist across or between requests. I know, it is a shortcoming of php, but on the other hand, the speed and stability of the individual requests help make up for this shortcoming.
Edit:
After reading over your question again, I realized you may not be asking for a singleton database access class, but rather something that can resource lock your database? Based on what you said, it sounds like the database may do the locking for you anyway. In other words, it won't allow you to connect if there is already another connection. If that is the case, it seems kind of like you have 2 options:
1) just let all your pages contend for the resource, and fail if they don't get it.
2) Create a queue service that can accept queries, run them, then cache the results for you for later retrieval.

Related

How to pass user data to service from controller using PHP-DI

My controllers have an account object and a user object, and almost all interactions with the backend depends on these objects to set access rights, limit data loads, ++++ (I am not using any specific framework)
My controllers have different ways of knowing which objects to use, but usually this is in the session for logged in users (but backend processes might get this information from the queue etc).
So, I am trying to setup PHP-DI for my ServiceLayer and I need to inject Account, User object to the services, but how do I do this in a good way ensuring that these have the right values?
My first attempt was to pass this into a ContainerFactory:
public static function getInstance(EnvironmentConfig $config, ?int $accountId, ?int $userId):Container
Then use these values dynamically in the configuration, however this stopped working when I enabled compilation as the values got cached. (obvious but yes..)
I can use a factory for creating the userObject and Account object and e.g read the values directly from the session in the Factory. But this feels very dirty, and will only work in certain contexts.
The documentation only deals with environment specific values, so I have not found any good description with how to deal with session specific data.
Any suggested patterns for this?
A container should store stateless objects. Request-specific data like session, logged in user, etc. are not dependencies, trying to put them into the container means going back to global state.
I highly recommend you pass that data through other ways: method call parameters, store them inside a Request object, at worse inject a RequestStack or similar object. That's what Symfony did when they deprecated injecting the Request objects directly using the container: https://symfony.com/blog/new-in-symfony-2-4-the-request-stack
Thanks for your quick reply. Principally I do agree, these things are border line as they are intrinsic to all application layer, the application has a global state depending on logged in account and user and that remains like that for the entire session. Yes this is technically request specific, but I need the service layer to be aware of this as so much business logic depends on it.
method call parameters would be technically clean, but super-messy and error prone as this would be the same parameters repeated all over in the application. All the service calls would end up like this:
$service->getCategory($id, $user, $account);
$service->getCategoryByMain($mainCategoryId, $user, $account);
Hence I was looking at PHP-DI to get a cleaner injection than my current setup where I get long Service constructors that are the same all over in the application.
Not sure how to make this neat, so open for any good practical suggestions :) Maybe PHP-DI is not the right tool here, but this is DI problem, where I have a set dependencies that needs to be pushed down in the stack.

Php global variable across the whole project

I'm relatively new to PHP, and I'm looking for a way to define certain objects as globally accessible from throughout the project, from multiple PHP scripts.
In Java, if I've to access some objects globally, I define some public class named Globals , and define the objects that I need to access as static in the Globals class. I then access those objects wherever I need with: Globals.variable_name .
So basically, I need to initialize these global objects only once and then use them whenever I need them..
One use case:
I've a class named Logger that has methods to log certain events in a log file. I need to have 1 Logger instance/object that can be used by all the PHP scripts in the project, whenever they've to log something. I'd rather not have each PHP script using it's own instance of Logger.
The naive Java-like approach I tried, that did not work:
I created a public class named Globals in a separate PHP file (named Globals.php) with one static object of type Logger, named $logHandle. I included this PHP file in all other PHP files where I need this Logger object. I then tried to access this object , using Globals->logHandle from one of the other PHP scripts. This attempt failed miserably.
Is there some similar approach?
Thanks.
PHP is not Java.
In web applications, the PHP environment is initialized for each request - and each request is handled in a different process with it's own memory space. It is possible to share access to data (including serialized objects, but not resources such as database connections and file handles) across different instances. You probably know this already but have not yet realised how it influences the way you write code.
I'd rather not have each PHP script using it's own instance of Logger
Why not?
One very good reason is that allowing multiple processes to write to the same open file handle requires locking to prevent the file getting all mesed up. BUT THIS IS PHP - STOP REINVENTING THINGS FROM SCRATCH. Writing to stderr will append the details to the webserver error log or use the OS syslog facilities - that's what they are there for.
It is impossible to have the same object available to all instances of PHP - you can unserialize an object in all instances - but then it's not the same object. You can run a daemon with a single object which might be accessible to all other PHP instances via a socket connection - but it's not running in the same address space.
If you validly have a class that you want to be universally available via an object with a fixed name, then simply create an instance of the object in each script or via an include file. The approach you tried is the way to go about this (but don't name your objects with reserved words). We don't know why it failed because you didn't provide any error messages or code.
I assume you're asking about common case (now only web-oriented application). And for that - no, you can not define some thing like you've described, in native way. This is the thing that is called superglobals in PHP.
But on the other hand - you need to do that for some reason, not "just because you want it". And, if so - then use configuration file. Create some application configuration file, read it once at start of application (bootstrap) and you'll get all needed values. I'm not saying anything about file structure - it can be xml/ini/yaml/whatever/you/like. But the idea is - to split this logic from application structure itself and use separate file for storing desired values.
Another option is to use some separate PHP file(s) and include it at bootstrap. Define all needed variables/constants in that file(s) and you'll get similar behavior. Note, that in terms of namespaces it's less "global" and you'll need to resolve all that cases manually.
For web-applications, however, one of possible solutions may be using sessions. $_SESSION is a superglobal array and it will behave like you want (i.e. will be accessible from everywhere). But that is not applicable always - and not always you'll want to deal with sessions to store session-independent data.
you can do like this
you said that you have included in all other classes change methods in your global class to static
<?php
class Logger {
public static function log($msg) {
// ...
}
}
you can use it like
Logger::log($msg);
http://www.php.net/manual/en/reserved.variables.globals.php
i think that is what you're after.
To access a static attribute in PHP you need to call it with the Class::$attribute notation, and the static methods need to be called with the Class::method() notation.
The -> notation is used when calling attributes of a class instance.

Do we need to have persistant object to achieve singleton pattern in php

I am having singleton Database class in classes/database.php as mentioned in Singleton pattern in php and I am creating the database object in users.php using Database::getInstance() method then I am calling the same static method in accounts.php (Database::getInstance()), here I am getting new instance instead of the instance that I created in users.php. I am new to design patterns and confused a bit.
my questions are
Do we need to have persistent object to achieve singleton pattern in php?
If not then what are all the ways that we keep the single instance all over the application.
Desktop applications often use a single database connection that persists. However, in PHP and most other web languages/frameworks this should not be the case. Instead of a single long lived connection, you use a short lived connection for each page load. Rather than thinking of your application as a whole, think of the process of each page load. In PHP, no other page load knows about the other unless you persist the data in a database or in $_SESSION or other places.
The singleton pattern in PHP is one of singleton throughout the page load. Although initially it may seem like "What's the point? Its just a page load", when you get to larger applications, it becomes obvious that each page load is not an insignificant operation. In systems like Drupal, you can have 10's to 100's of database queries happening each page load
Oh, and the singleton pattern is considered Bad Practice and will bite you later. In fact, it should probably be avoided in all of your applications. A better pattern would be something like the DAO pattern or the Factory pattern. Please, save yourself and don't use singletons (I've made that mistake so many times).
As for persisting objects between page loads (which is very necessary to almost any application), that is what your database and $_SESSION variable is for. You could also use alternative caching options like APC (http://php.net/manual/en/book.apc.php). Your application should be able to re-construct what it needs to based on whatever it finds in your database. For example, a user is created. You persist that user's data to the database. Whenever someone comes around and wants to know about the user, it pulls it out of the database to re-create your user object. Another example is that a user logs in. You want them to stay logged in, so you persist some kind of variable to $_SESSION that is checked every page load to see if they are logged in and who they are logged in as. You do some checking and then load the user that they say they are logged in as from your database.

PHP PDO: Multiple objects extend dbwrapper; How many MySQL connections?

The Situation:
I am using a db class as a wrapper (dbwrapper) to open and close db connections via PHP PDO
I have 3 separate classes which extend this db wrapper
I instantiate 3 objects from said classes and in the course of their existence they each make db queries
MySQL used in this case.
When the methods of the 3 classes require db access they each create PDO objects internally, making use of the dbwrapper which they extended. Each object is storing its PDO object in a member/field for reference by itself.
The Question: My question is this... is each object creating a separate connection to the database, making 3 in total? Is each client of Apache creating only one connection to the database or is each object using the db in a php application creating a connection. (sounds inefficient!)
The Reason: I would like to understand how these connections are handled.
I am trying to decide if it would be better to have each class extend the dbwrapper or if it would be better to initialize the dbwrapper without making an automatic connection the db, handle that when its needed. Instead I would pass the dbwrapper to each objects constructor as they are initialized... letting them use that reference. If multiple db connections are happening then I think this would be the best way to minimize overhead while overcoming issues of object's scope and access.
Thanks in advance!
is each object creating a separate connection to the database, making 3 in total?
Maybe. I don't know, but here's how to find out. While your script is running, connect to MySQL via your client of choice (like the command line) and issue the command SHOW PROCESSLIST; You'll get a list of active connections.
You might need to insert a sleep in your script to keep it alive long enough for you to run the process list command when you've instantiated and are working on all three objects.
You'll see either one connection or three. Then you'll have your answer.
(The answer will vary depending on the underlying driver. Some drivers will reuse the connection if the DSN is identical.)
Instead I would pass the dbwrapper to each objects constructor as they are initialized... letting them use that reference
This is the common practice. Database handles are prime candidates for the Singleton pattern as well.

My logger keeps getting destructed while I am trying to log errors and exceptions

I am just now switching back to PHP after enterprise open-source Java development for three years. Now I am tasked with updating our platform for better logging.
I now understand better how the PHP object lifecycle regarding when objects are garbage collected and have trapped my problem. I am trying to invoke the logger after its already been destructed, when a fatal error occurs. My question is, how do I fix this? How can I stop an object from being destroyed until the end of the request?
Ideally I would like to keep this logger around in memory like I would in Java but is that even possible with PHP? Is there anything shared between two different threads or requests?
With PHP, each request is processed by a different process -- which means you quite cannot keep some object arround between requests (you could serialize it and store it in a file or something like that, and un-serialize it when another requests comes ; but that's not really the way things are generally done)
This means each time your PHP script receives a request, you have to re-instanciate your logger.
Now, if you want to use your logger from several different classes/methods/functions in the same script, you have to know that variables are not global "by default" in PHP : a variable declared outside of a function is not accessible from inside a function, unless you said so using the global keyword.
In this kind of situation, when you want one and only one instance of a specific class (your logger) available from anywhere in your application, people often use the Singleton Design Pattern.
It'll allow to use something like this :
My_Logger_Class::log('blah');
From any portion of your code, and the log method will deal with :
instanciating the class if there was not already one existing instance
the actual logging
And, yes, the first time this method is called for one HTTP request, it'll have to re-open the log file (if logging to a file).
As a sidenote : there are already some existing great logging components, like PEAR::Log or Zend_Log.
Maybe using one of those might help you spend less time re-inventing some wheel ?

Categories