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.
Related
I have a master class, DBAPI which contains all the interaction with the database. It's not singleton per se, but is designed to only be instantiated once as $DBAPI.
When I alter the database, I obviously have to add functions to DBAPI to let the site use the new functionality, however, since there are a lot of different actions that can be taken, instead of including everything in a single massive class file, I've split them out by functionality/permission level as traits, and the DBAPI class file is dynamically created by adding traits flagged based off of permission level (read only, read-write etc.). Since the only time the file needs to be created is when new traits are added, I only create the class file if it doesn't exist for that specific user permission level, otherwise I use the already generated file. (If there's a better way to do this I'm all ears).
The issue I'm running into now is that if I add some functions in a new trait, the previously generated classes are obviously not aware of it, and I don't find out about that until I try to use the function in the code somewhere and it fails. It's pointless to write wrappers around every single function call made to check if it is a function first- is there some way to get the DBAPI class to do some action if code attempts to access a method it can't find?
for example, if code calls some function $DBAPI->newfunction() $DBAPI handles the exception itself, running some code that will attempt to update itself, which will cause newfunction() to run if it can be found.
(N. B. This architecture has a really bad code smell. I'm sure there's a better way to do this.)
PHP classes can implement the __call magic method that is used when there is no matching method name.
function __call( $name, $arguments ) {
// Code to run...
}
I'm working on a PHP IRC Bot, and I'm currently working on the commands.
At the beginning of main.php, the script that starts the bot, it includes the class_lib.php file and instantiates the object of that class. I want to work on a !reload command, where it would "uninclude" the file and then reinclude it. Would that be possible, or would it be fine if I just included it again when that command was sent?
EDIT: Basically, I want to be able to modify and reload the class without having to restart the bot.
No, you can't. Revisit your design. Don't couple the definition of the class with the instantiation of the object.
Why not just allow the object to reload the default settings, or restart, instead of what you describe? I'm pretty sure you can't do that anyways.
Also, don't try to load the object with the class_lib.php. Include the class file with the object, then where and when you need it, create your object. That way you can stop it, destroy the object, and then re-instantiate another object, which should accomplish what you want.
Am afraid there is no way to uninclude a file. If it is a function, you could generate a new function dynamically each time.
Check:
http://php.net/manual/en/function.create-function.php
You can assign a function to a variable and then clear that variable and assign it again.
Late to the party, but I have to mention the following PHP-extension:
http://www.php.net/manual/en/book.runkit.php
The runkit extension provides means to modify constants, user-defined functions, and user-defined classes. It also provides for custom superglobal variables and embeddable sub-interpreters via sandboxing.
This would allow you to re-define classes, which happens upon parsing included files.
NOTE: I have not used this, I came upon it after researching if it was possible to somehow hotswap certain classes. I cannot vouch for the safety and can not supply hands-on info. Yet.
Late answer..
You could create an array containing the files and then eval(file_get_contents($filename))
I've been working on my own IRC Client named PITC and that may be the method I might use, It's how i've done stuff before
I'm writing my first basic bare bones MVC patterns setup in PHP. I know global variables are bad, and I aslo know I don't want all of my classes to have access to all of my config vars.
I have a settings.php file that I would like to define a bunch of constants in, like my db connection info, directory structure info, email addresses and so on. It will be one centralized location that holds all of my important information.
What's the best way to implement a config class so that each of my base classes for my controller and model only have access to the config vars they need? For example, my model base class should have access to by db connection info.
Basically I am just asking how anybody whole rolls their own MVC setup handles config information without declaring global variables, like we used to back in the procedural days.
Thanks.
You're going to get a bunch of answers on this as it basically boils down to preference.
Personally, ive used a config array. example:
$conf['db']['username'] = "username";
$conf['db']['password'] = "password";
Then just pass byref the pieces you need into where they need to go.
I rolled my own MVC setup. (Still going strong. Might open source it). The way I do it is to have an init script that passes all those constants to a controlling class.
The controlling class is a Singleton. So anytime another class needs access to it, it just gets the existing instance of the controlling class and all the variables are available from it.
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.
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 ?