Persistent objects in CodeIgniter - php

I have an php object which I want to be accessible whenever I want. I want to create this object once and keep it persistent so that I don't have to reload it again. Also I would like this object to be accessible in my controllers/models etc.
Can this be achieved in CodeIgniter/PHP without using session?
Or maybe using session, but will I be able to access its methods?
This object is created using PHP COM library from my dll file
Here is sample of my object:
$myDllObject = new COM("MyDLL.MyCLass");

PHP has an execution model where each web request from the host environment generates a new, fresh PHP environment which is destroyed when the request is completed.
So the simple answer is no, you cannot create an object and persist it between requests. You must "persist" the object in some other way:
Through serialization/deserialization, using sessions, a database, a key-value store like APC, a file on the file system, or some other method.
By having a separate long-running process hold the object, and having PHP objects communicate with it via some IPC method, such as shared memory, pipes, sockets, etc.
I don't know much about COM, but since COM objects can be created outside the running process I suspect that there is probably some (not-PHP specific) method of connecting to an existing one rather than creating a new one. (This is essentially option 2 above, using the COM services as the IPC.)
A little digging through the PHP COM library docs reveals the com_get_active_object() function, which may bring you to a working solution. However, you will probably need to learn more about COM from non-PHP sources. Also, read the big fat warning about using a single COM object concurrently:
Using com_get_active_object() in a web server context is not always a smart idea. Most COM/OLE applications are not designed to handle more than one client concurrently, even (or especially!) Microsoft Office. You should read ยป Considerations for Server-Side Automation of Office for more information on the general issues involved.
This suggests to me that creating a singleton COM object shared among all requests is actually what you don't want to do!
If that doesn't work, PHP has an object serialization method that allows you to serialize the running state of an object to a string and deserialize it back again to the same state. You can customize this by adding the __sleep() and __wakeup() methods to your class. This mechanism has it's share of quirks and I don't know how well the PHP COM library proxy objects would support it.

I'm not very familiar with the PHP COM library but if it's a object couldn't you maintain it's state by creating a object in your base controller and creating it there. Then just extend your other classes from your Base class.
class Base_Controller extends CI_Controller
{
public $myDllObject;
public function __construct()
{
$this->myDllObject = new COM("MyDLL.MyCLass");
}
}
/* End of file MY_Controller.php /
/ Location: ./application/core/MY_Controller.php */
Example Controller
// ------------------------------------------------------------------------
class YourController extends Base_Controller
{
public function __construct()
{
if (is_object($this->myDllObject))
{
echo 'Yep';
}
else
{
echo 'Nope';
}
}
}

See the CodeIgniter documentation on Creating Libraries.
Once your library is created you can choose to have it autoloaded in config/autoload.php, or, you may load the library using $this->load->library('yourlib');
If you need to create a new instance of this class on every page request, consider putting the instantiation in the constructor of your controller. Or, create a base controller class and put it in that constructor.

Related

What's the preferred way of having an object available everywhere in PHP?

The project I'm working on requires me to have some objects, including an event manager, (read-only) configuration manager and plugin manager, that are available everywhere in the system.
I was using global variables for these, until someone (with a C++ background) kindly pointed out that "You're probably doing something wrong if you need global variables".
He suggested using a state object that's passed to all functions that need it.
So I did:
$state = new State();
$state->register('eventManager' , new EventManager());
$state->register('configManager', new ConfigManager());
$state->register('cacheManager' , new CacheManager());
$state->register('pluginManager', new PluginManager());
$state->get('pluginManager')->initialize($state);
While I can see the benefit of this method in more stateful languages, it seems kind of pointless to me in a (mostly?) stateless language like PHP, where the state is lost after the page is done loading.
Is there any benefit to passing a state object around in a (mostly) stateless language like PHP, does it hold any benefits over other approaches (i.e. a globals-based system) and are there better ways to handle this?
The registry that you propose is still a global variable. And if you want to access a global variable (even if it is an object, although a global one), you are doing something wrong.
A proper application only has on phase where global state plays a role: When bootstrapping it. The request starting the script is global, any request data sent with it is global, and any configuration that affects the application and is stored in a file or some other appropriate storage is global.
The first phase should initialize some dependency injection that puts all the parts that make up the application together. That object graph would be created on demand when the processing of the request has decided which part of the code should be called to respond to the request.
Usually this decision is done inside a framework processing the request, and the dependency injection likely will be also done via a framework. Your own code would only accept either the values needed to operate, or the other objects that are needed.
For example, if your code would need a database, then you'd configure the database object to accept the URL and credentials for your database, and then you'd configure your reader object to accept that database object.
It would be the task of the dependency injection to either create only one single database object, or multiple of them. You don't have to use the outdated "singleton antipattern" because it has many drawbacks.
So in this scenario, there are some objects existing in the dependency injection part that are only created once and injected when needed. These objects do not enforce to be only created once, and they are not stored inside a globally accessible variable. However, something has to live in a global variable, but this is only the main framework object and probably the dependency injection container, and they are never shared into the remaining code as a global variable - so this is not harmful at all.
One way to do this is with singletons:
class ConfigManager {
private static $instance = NULL;
public static function getInstance(){
if(self::$instance === NULL) {
self::$instance = new ConfigManager();
}
return self::$instance;
}
private function __construct(){
// Notice that this is private - only getInstance() can call this.
}
}
// When you need it:
$config = ConfigManager::getInstance();
There are many different opinions on how to do what you're asking - and I myself don't think singletons are always the best way to do this, either. It really depends on your use-case.
That said, singletons are just one common pattern for a class whose instance is supposed to be accessible everywhere.

Caching an object that has used Dependency Inject (DI) in Phalcon

Phalcon is a decoupled PHP framework that allows services to be injected via the DI container. They have several default services, but also allow you to define your own services as follows:
$this->di->set('my_service',function(){
return new myService();
});
You can then call the service in the application in a couple of different ways:
$my_service = $this->di->get('my_service');
Or
$my_service = $this->di['my_service'];
My application utilizes the dependency injector along with another feature of the Phalcon framework, a data cache, and these features don't play well together.
As soon as you call a service via the DI in a class, the DI parameter of that class is established. If I try to cache that object, I get an error Serialization of 'Phalcon\DI\FactoryDefault' is not allowed. I've done some searching, and can't seem to find a solution that will allow me to utilize dependency injection and caching on the same object.
The whole code ends up looking something like this:
//In bootstrap file
$this->di->set('my_service',function(){
return new myService();
});
//In another class
class myclass extends Phalcon\Mvc\User\Component
{
$cache;
public function construct(){
$cache = new Phalcon\Cache\Frontend\Data(array('lifetime'=>24*3600*5));
$this->cache = new Phalcon\Cache\Backend\File($cache, array('cacheDir' => '../app/cache/'));
$this->di->get('my_service')->someAction();
$this->cache->save('myKey',$this);
}
}
Is there a way to get around this issue?
I believe the problem is caused by the use of anonymous functions to register services. This is because the application doesn't know what's inside the function until it's actually run, so the factory default DI can't be serialized.
One option would be not to extend the Phalcon Component class, and instead inject the required dependencies as constructor parameters. This way when you serialize your object you're not also serializing the DI (which currently is being inherited through the Componant class).
You can have Phalcon automatically inject the required dependencies by setting it up as part of its service registration in the bootstrap file.
Another option I can think of would be to use a different Frontend cache adapter that doesn't serialize the data:
http://docs.phalconphp.com/en/latest/api/Phalcon_Cache_Frontend_None.html

How to access libraries inside a controller?

I'm building a small framework that I can use for repeated mundane stuff on future small projects.
I'm stuck on the best way to access libraries from inside a controller. I originally implemented a system similar to CodeIgniter's whereby my main controller class is basically a super object and loads all the classes into class variables which are then accessed by extending the controller and doing like $this->class->method()
I find that a little ugly, though. So I thought of just loading each class individually on a per-use basis in each controller method.
What's the best (cleanest) way of doing this?
To only ever have one instance of each class, you could create a simple service container.
class ServiceContainer
{
protected $services;
public function get($className)
{
if (!array_key_exists($className, $this->services)) {
$this->services[$className] = new $className;
}
return $this->services[$className]
}
}
Then create one ServiceContainer instance per application. Inject the container into all of your controllers and use
public function someAction()
{
$this->container->get('Mailer')->send($email_data);
}
Simple example, and obviously needs a lot of work to make useable (for instance autoloading needed and handling of file paths for ease of use, or easier way to add services without getting them, etc).
I dont like the way CodeIgniter does it. Its never seemed right to me. I favor an auto loading class pushed onto the spl_autoload stack. And then just calling the class as normal like:
$class = new SomeClass();
PHP provides autoload functionality with SPL and spl_autoload (and related functions). You can register a custom autoloader for your library code.
For the shared functionality handled by your application, have you considered the Front Controller design pattern?

Where are the instantiated objects stored in zend framework?

I'm a beginner in Zend Framework and I find it hard to understand their documentation.
The only PHP Framework I have used was CodeIgniter.
I am used to this method in utilizing libraries:
//load the My_Library class and assign the object to $this->myLibrary property
$this->load->library('my_Library'); //CodeIgniter way
public function index()
{
$this->my_Library->method(); //make use of the methods in the loaded library
}
So far I'm figuring out how this code works in zend, say in the bootstrap class:
protected function _initSetDoctype()
{
$doctypeHelper = new Zend_View_Helper_Doctype();
$doctypeHelper->doctype('XHTML1_STRICT');
}
And in the layout.phtml file we can put:
<?php echo $this->doctype() ?>
My question is: Since I have instantiated a new Zend_View_Helper_Doctype();
How did ZF assign $this->doctype and made this available in view?
Is there some kind of storage where these values update the view object?
I'm trying to find out how the flow works in zend so I could have a better understanding on how to make use of its resources. Sorry for my English if it's hard to understand #_#
Thank you very much!
Usually ZF uses Zend_Registry to store instances of objects that it creates. The specific example that you provided (i.e. _initSetDoctype) works, because constructor of Zend_View_Helper_Doctype will check if it is already stored in Zend_Registry or not. So, in your bootstrap, new Zend_View_Helper_Doctype() will store doctype info in a registry (because it is created for the first time), and than in the layout.phtml, the stored value in the registry will be retrieved.
Other ZF resources (or objects) such as Zend_View, Zend_Layout, are also stored and access through registry.
Off course, you can also store your own objects (or whatever) in a registry. This way, you will be able to access them in every place of you ZF app.

Adapters and Dependency Injection

I am currently building an MVC application in PHP (not using any frameworks). I am using yadif (https://github.com/beberlei/yadif) for dependency injection.
I would like to build a login module. It should be able to use adapters, for example one might be able to set that logins are authenticated using the MySql database or some LDAP directory. This setting would be done in the admin area and is stored in a database.
I imagine that I would have an abstract adapter:
<?php
abstract AbstractLoginAdapter{
abstract function login($username, $pass){}
}
I would then just implement adapters like so:
<?php
MySQLLoginAdapter extends AbstractLoginAdapter{
public function login($username, $pass){
//do stuff
}
}
That's all nice and well, but how do I create an instance of the adapter? Usually, dependencies would be injected using yadif via the constructor:
<?php
class loginController{
private $_adapter;
public function __construct(AbstractLoginAdapter $adapter){
$this->_adapter = $adapter;
}
}
However, since I don't know which concrete adapter will be injected, I can't set that in a configuration before hand. Yadif allows me to create a configuration which I then need to pass to the container:
$builder = new Yadif_Builder();
$builder->bind("loginController")
->to("loginController")
->args($SelectedLoginAdapter);
Since the application uses a front controller, a DI container is created there. It then creates a routing object etc.
In light of this, should I pass a reference of that container down to the loginController object, and then use that container to instantiate my adapter?
Or should I instantiate a new container within my loginController object and then just load in an instance of the adapter?
I would do the first: pass a reference down to your controller. You'll want to use a single Dependency Injector Container (DIC) in your application. You don't want to create a new DIC whenever you need access to it. That would lead to duplication of objects stored in the DIC.
I know this is how Symfony 2 does it. All controllers (and many other classes) implement the ContainerAware interface. That interface has a single method setContainer() that is used to pass down a reference to the DIC.
I don't know about your specific DI tool but from a DI point of view you would be specifying which type to use. The container itself is responsible for instantiating a new instance (and possibly of all the dependencies of that type as well) of the configured type.
The benefit of DI in your example would be that you could deploy exactly the same code with a different configuration with 1 installation using LDAP and the other using MySQL authentication.
Refactor type hinting ("AbstractLoginAdapter") to ("MySQLLoginAdapter").
If you call abstract class method in the new __CLASS__ // Fatal Error.

Categories