Overloading static properties with PHP - php

I'm trying to automate the process of accessing libraries in the framework I use (CodeIgniter) but am running in to some issues.
Codeigniter currently loads libraries like this:
$this->CI->load->library('name');
$this->CI->name->method();
Needless to say that this is a whole bunch of code for something that could be achieved with far less.
I would like to access my lib like this:
_Lib::name->method();
The _Lib class will then take care of loading the right lib (or directing the loading of that lib to the loader class in this case).
However, above code results in error "unexpected T_OBJECT_OPERATOR".
My end goal is to be able to talk to libraries and have them load on-demand with as little code as possible, and without initializing a global variable.
Any ideas? Keeping in mind that it needs to look as usable and self-explanatory as possible.
I'd like to avoid using something like _Lib('name')->method() as it's quite tedious to write that every time.
Edit:
I ended up creating a default Library which I extend my Libraries from, the default Library has properties which direct the loading of other libraries (or models, or helpers, or .. etc) to the appropreate loader, so I can do
$this->lib->name->method();
Thanks everyone for your answers

The way you've written it, _Lib::name is a class constant. Did you mean _Lib::$name->method(); ?

The "unexpected T_OBJECT_OPERATOR" error means that your call to _Lib::name did not return an object from which to chain off the method call. Technically, _Lib::name returns the value of the class constant name in _Lib. You are trying to do
class _Lib
{
const name;
}
_Lib::name->method();
but a constant cannot hold an object, so no ->.
You do not want to convert your library to static calls, because anything static couples to the global scope and is much harder to test. Just keep using what CI offers out of the box.
If you want to have one class to globally manage your other classes, consider using a Dependency Injection Container, like the one offered in Symfony Components.

Related

Should PDO Instance be static or not [duplicate]

In my example I'm using the PHP framework Yii2 but I think this applies to most OO languages.
I have an ActiveRecord base class which most of my business objects extend from e.g. Project.
At the moment if I want a Project instance I call
Project::findOne(['id' => $id]);
findOne is a static method of ActiveRecord (which is part of the Yii2 framework). So this is bad form because I can't easily mock/stub the return of this call when writing unit tests.
But what's the best way to get around this?
I could create a class CActiveRecord that inherits from ActiveRecord and wrap the static call in a non-static call and use that everywhere - but then I would have to instantiate a throw-away Project object in order to get the actual instance. What if the Project object needed some heavy config to be instantiated - I would be passing random nonsense into the constructor just to get an instance.
Summary:
Simply changing statics to non-statics seems wrong - shouldn't I also move the functions somewhere else? If so, where?
The issue with static calls is the hard coupling to a specific other piece of code. Just wrapping that in a "dynamic" call doesn't make this any better:
$c = new CProject;
$c->findOne(); // Calls Project::findOne()
That's pretty darn pointless. The issue is not the syntax of -> vs. ::, the issue is that this particular code references a specific other class and that you cannot easily exchange this class for something else. You're building rigid, hardcoded dependencies between your classes/objects, which makes it hard to take them apart, which makes your code hard to test, and which makes it harder to adapt code to different situations.
The alternative is dependency injection:
function foo(Project $project) {
$p = $project->findOne();
}
This function is not coupled to any one specific Project class, but to a class which simply offers an interface akin to Project. In fact, Project could even be simply an interface. Which specific class and method is getting called here then is decided somewhere completely different, like your dependency injection container; or simply the caller of this code.
This makes it a lot easier to take this code apart and put it back together in different ways, as necessary for the situation at hand. That's not to say it can't work and that you should never use static calls at all, but you really need to be aware of what cross-dependencies you're establishing with every hardcoded class name, and whether that may or may not cause a problem down the line. For even moderately complex and/or growing software projects, it will almost certainly cause friction in some form or another eventually.
See How Not To Kill Your Testability Using Statics for a longer in-depth article.

Grouping/encapsulating related functions that are across multiple php files

I'm working on an app, and part of functionality of this app is that it is extendable through addons.
The main app uses has a Render class that contains a lot of static methods that have to do with output. The actual methods interact with models/views, but the basic idea is that the Render class encapsulates methods that render something, like:
// To output "hello"
Render::sayHello();
// To output a picture of a cat wearing a hat
Render::catWithHat();
Now, from time to time addons require their own unique output functions. These output functions are very similar to the Render methods. So...
My first thought was that it would be great if I could dynamically add methods to the Render class, but after reading up about on-the-fly method creation it sounds like that's generally not considered very good practice.
So then I thought, well, I could just not encapsulate the addons' render functions at all. So that you'd just call them like:
renderMyAddonOutput();
I don't love that idea either, though.
So I guess I'm just wondering what would be considered best practice for encapsulating related functions that are declared across a variety of files.
Thoughts?
Note: if it makes any difference, I'm using Laravel for this (the very latest version).
I would consider using a Plugin pattern where an add-on registers itself into some kind of static container on init, and then you can use PHP's magic method __call() or __callStatic() to check the plugin array when a method is called that isn't found in the base class..
So if you had:
Render::pluginMethod()
then __callStatic() would check your plugin registry (which can be as simple as a static array of plugin classes or methods) and if it finds that method, it calls/returns it.

How to use one object in another class : PHP framework

This is my current system for a framework that I'm making:
I create an object upon a request to access a non-existing property, that has the name of an existing class through the __get function defined in the Core class. The Core class extends every class.
So it works like this:
class Someclass extends Core
{
public function classmethod()
{
$this->otherclass->method();
}
}
This works exactly how I want it to work. However, I have no idea (after a lot of frustration) how to edit/create properties of the object, using this system.
So something like this would't work.
$this->view->somevar = "newvalue"; // this doesn't work.
I guess it has to do something with the __set function, but I failed to find out.
I received the following suggestions how to tackle this problem:
Dependency injection, Namespaces, Singleton pattern.
I would love to see how to implement what I'm trying to do using one of these patterns.
I have no idea which to choose in order to achieve my simple problem: Use objects in other classes, so i don't need to put anything into __construct's parameters or using global variables.
I am using __autoload.
I hope i can tackle this problem with your help.
First of all, the architecture you're attempting is extremly bad. Aparently you are using "magic" to create objects attached as properties to other objects. Which is bad, because if you use _get/_set, you will end up in problems sooner rather than later. Also extending from a common parent is a bad thing because it generates huge inheritance trees, and it allows most of the objects to have more than one responsability.
Before starting a framework, you might want to look over: SOLID
Now coming back to your question, if you use __get for getting a value, you can as well use __set for setting a value.
__construct method is there in order to allow you to initialize the object with all the data it needs in order to fulfill his sole purpose. Avoiding the __construct is kinda stupid, and defeats the purpose. You might want to pay attention to the D in SOLID in order to see what Dependency Inversion really is and to understand it.
Using __set loses completely the ability to typehint interfaces and so on. Therefore the code can become really buggy and ijcredibly hard to follow, since the flow is not so well defined, and the allocation is done in the back via magic. Also i can come up with 1 million other reason for which the architecture you are trying to use is wrong, but i will leave that for another time.

Static methods or not?

I need to develop a small CMS using PHP, and right now I'm trying to figure out the structure.
The CMS will be generated using a set of functions. Things like database functions, caching thingies, internationalization and stuff like this.
I was thinking to do it like this:
make the functions non-static methods part of a big "site" class; that way I could run multiple instances of that class. Not sure I would need to do that though..
or split the functions into separate classes with static methods
The main problem here is that the CMS should be able to manage multiple small sites, not just one. So either I make all methods static and add a "site switch" function, or make them normal objects which I instantiate based on the site which I want to manage
Which of these would be the best option?
Static methods are generally bad practice. They introduce a lot of potential issues.
1) They introduce hidden dependencies. Code which arbitrarily calls foo::bar() has a dependency on foo and cannot run without foo being defined. The object using foo::bar() will construct correctly but won't be usable if foo is not defined.
2) Statics are globals. Global state is very bad, anything can change the code and its state is unknown. You sacrifice the power and control achieved by OOP encapsulation by using static methods.
3) It's impossible to substitute the functions for a different version
4) It makes unit testing impossible.
For more detailed information and code examples, see this article and this article
I'd definitely suggest using static classes for this job. Going this route will create a pseudo namespace for all of your functions so you don't have to worry about conflicting function names, etc, and it also prevents you from having to pass around an instance of your helper class just to call one of your helper functions.

Confused About Objects and Classes in CodeIgniter?

I’m fairly new to CodeIgniter and have a question. I’m a bit confused about Classes, Libraries and Objects.
Does CodeIgniter replace the normal PHP way of usings objects i.e. $var = new car(); with libraries i.e. $this->load->library('some_library'); $this->some_library->some_function(); ?
If both are valid, is there a difference? If so, what are the differences and when do I use one over the other? Which is more common/proper?
I am asking because I created a class, but I'm not certain what is the correct manner in which to instantiate it.
Thanks in advance
I am not familiar with CodeIgnitier. But familiar with other PHP frameworks. Most of frameworks use this way for performance improvements, registering things, executing certain events, and making things simpler for developer...
For example if you want to create class "car" with is somewhere in library directory you would have to include the file first before you can create object of that class (miltiple lines of code, more room for error). The framework will create the class and includes related files in 1 line of code (easier and safer).
Framework way also works as a factory. Instead of recreating an object, it will create object only once and every time you call the method again it will return the reference to existing object.
More things are happening behind the scenes when you use framework. Things are getting registered, etc...
CI doesn't replace class behavior per se, it simply adds functionality that allows access to custom libraries/models/views as singleton objects via the core object for simplicity.
Nothing is stopping you from creating (as I have in one of my projects) additional files with classes for non-singleton entities and require them in a model for further use. On hindsight, I should probably have used helpers for this.
What the loader ($this->load) class does, among other things, is it creates a single object of the specified class (model, library or view - not helpers though, see below) and attaches it as a property of the core class that is normally accessible via $this.
Helpers are a bit different. They are not attached, but instead simply 'read' into the global namespace from the point where they are loaded.
To answer your question, it would be more proper to use the loader class in instances where you don't need more than one instance of a class created. If you need 'entity' classes, your best CI-compliant bet would be to create them as helpers.
Given only this context, this looks like Inversion of Control (maybe I'm wrong, I haven't looked too closely at CodeIgniter).
You don't want to rely on the type car as in new car(). What if later you want to make $var a racecar? $var can still do the same things, but it is forced to be a car because you constructed it directly. Or what if you are testing this class, but car is some complex object which calls some external service. You want to test your logic, but don't care if the car service isn't working. So you should be able to change $var to actually load a mockcar. You can't do that if you do $var = new car().
What is Inversion of Control?

Categories