How do I make 15 static PHP classes work together well? - php

I have a personal PHP application that has about 15 classes. Each class is only initiated once as a page is executed. In other words, when the page loads:
15 classes are loaded, and as each class file gets loaded, I create one instance of the class.
The application (so far) is designed so every variable in the system has one state during the generation of a page. I use global vars to access each of these
It's worked fine for 3 years, but I am the sole developer and a goo debugger of my own code.
I have heard all the issues with Singletons, and I hate doing, "global $var" all over the place. Please tell me how to pull this type of structure out and into something developers would love. I want to write software the right way, but I can't seem to find a very simple code framework for this type of execution.
Oh - and I'm not looking for a MVC framework solution. I would love your thoughts on how I take 15 classes and turn them into a proper framework for working together. I would also love an articulation on how "stupid" it is to develop this way.

If you have variables you want all classes to have access to, maybe you could try inheritance, for example something like
class Settings
{
var $page_name = "My Page";
var $database_name = "my_db";
}
and then let all classes inherit this class like
class Page extends Settings
{
var $id = 0;
var $template = "";
function __construct() {}
}
$page = new Page();
echo $page->page_name;
or you could define the values as constants, if that is what they are
define("PAGE_NAME", "My Page");
you would have access to PAGE_NAME everywhere
I'm not in any way saying this is the right way, it's just a way. :)

I ran into the same issue when I was developing php apps. What I ended up doing was creating classes of static methods and static variables. In essence they work somewhat like namespaces. I am not sure how "standard" this is but it works very well in practice.
The only other option would be to create a singleton like you mentioned in your question, but imho that can be overkill unless you need something like constructors and deconstructors.
Example:
<?php
class MyClass{
private static $my_static_variable;
static public function myStaticMethod(){
return self::$my_static_variable;
}
}
You can then use this anywhere without the need to use global:
function foo(){
MyClass::myStaticMethod();
}
class Bar{
public function myBarMethod(){
MyClass::myStaticMethod();
}
}

I have been considering the same thing myself, and the only conclusion I could come to way to crack open an MVC framework and see how it's built.
The other thing is as mentioned, to start with a single super class and inherit down from there.
So have a class Object, then inherit that into something and so on and so on.

Related

Need some guideline to refactor my php code in OOP concept

I wrote a wordpress plugin that works fine. However, it just works but there is no OOP here because at that time it was necessary to build something asap. I read some literature and found that php do not support multiple inheritance due to diamond problem.
Current scenario:
Flickr
--pic importer
----1. sql.php
----2. javascript.php
----3. call to show database contents
--photoset importer
----1. sql.php
----2. javascript.php
----3. call to show database contents
Here, I have created 2 class: picImporter and photosetImporter. Both classes share common contents from (1. sql.php and 2. javascript.php) but point-3 (implementation of showing database content is differnt for them).
So, my idea is: I should create another class Global and photosetImporter, picImporter class should extend this class. In the Global class there should be an abstract class that child class must define. So the design becomes:
Class Global{
//$sql comes sql.php,
//$javacript comes javascript.php,
abstract protected function showDatabaseContents();
}
Class picImporter extends Global{
protected function showDatabaseContents() {
//implementation using **$sql** from base
}
}
Class photosetImporter extends Global{
protected function showDatabaseContents() {
//implementation using **$javascript** from base
}
}
Before I proceed, I just want to know if I am on right track or not and further instruction if possible.
Thanks,
-S.
There's no particular "right" way to do what you're looking for (though there are wrong ways). Hard to know what method I would use without understanding what your javascript class does.
Typically, I create a single global DB abstraction class (what I assume your sql class is) and just access it from the global scope wherever I need it. Global scope isn't evil, especially for things like database access which aren't inherent to whatever other classes you're creating but are needed pretty much everywhere. The same may be true for your javascript class.
That said, if you need this sort of abstraction to maintain a consistent design in your application, then I see no problem with what you're doing here, this seems like a logical approach.
If you're looking for what might be a best practice, run a search for "PHP design patterns", but in general my approach with PHP is to keep it simple and accessible. That may mean using a design pattern, or it may mean a more basic approach, depending.

Should I remove static function from my code?

My code is located here: https://github.com/maniator/SmallFry
Should I make it so that that the App class does not have to use static functions but at the same time be able to set and set variables for the app from anywhere?
Or should I keep it how it is now with App::get and App::set methods?
What are the advantages and disadvantages of both?
How would I accomplish that 1st task if I was to undertake it?
Related Question
Sample code:
//DEFAULT TEMPLATE
App::set('APP_NAME', 'SmallVC');
//END DEFAULT TEMPLAT
//
//DEFAULT TEMPLATE
App::set('DEFAULT_TEMPLATE', 'default');
//END DEFAULT TEMPLATE
//DEFAULT TITLE
App::set('DEFAULT_TITLE', 'Small-VC');
//END DEFAULT TITLE
//LOGIN SEED
App::set('LOGIN_SEED', "lijfg98u5;jfd7hyf");
//END LOGIN SEED
App::set('DEFAULT_CONTROLLER', 'AppController');
if(App::get('view')){
$template_file = $cwd.'/../view/'.App::get('view').'/'.App::get('method').'.stp';
if(is_file($template_file)){
include $template_file;
}
else {
include $cwd.'/../view/missingview.stp'; //no such view error
}
}
else {
App::set('template', 'blank');
include $cwd.'/../view/missingfunction.stp'; //no such function error
}
I think you have a feeling that static is bad. What I am posting may seem fairly crazy as it is a massive change. At the very least hopefully it presents a different idea of the world.
Miško Hevery wrote static methods are a death to testability.
I like testing, so for that reason I don't use them. So, how else can we solve the problem? I like to solve it using what I think is a type of dependency injection. Martin Fowler has a good but complicated article on it here.
For each object at construction I pass the objects that are required for them to operate. From your code I would make AppController become:
class AppController
{
protected $setup;
public function __construct(array $setup = array())
{
$setup += array('App' => NULL, 'Database' => NULL);
if (!$setup['App'] instanceof App)
{
if (NULL !== $setup['App'])
{
throw new InvalidArgumentException('Not an App.');
}
$setup['App'] = new App();
}
// Same for Database.
// Avoid doing any more in the constructor if possible.
$this->setup = $setup;
}
public function otherFunction()
{
echo $this->setup['App']->get('view');
}
}
The dependancies default to values that are most likely (your default constructions in the if statements). So, normally you don't need to pass a setup. However, when you are testing or want different functionality you can pass in mocks or different classes (that derive from the right base class). You can use interfaces as an option too.
Edit The more pure form of dependency injection involves further change. It requires that you pass always pass required objects rather than letting the class default one when the object isn't passed. I have been through a similar change in my codebase of +20K LOC. Having implemented it, I see many benefits to going the whole way. Objects encapsulation is greatly improved. It makes you feel like you have real objects rather than every bit of code relying on something else.
Throwing exceptions when you don't inject all of the dependencies causes you to fix things quickly. With a good system wide exception handler set with set_exception_handler in some bootstrap code you will easily see your exceptions and can fix each one quickly. The code then becomes simpler in the AppController with the check in the constructor becoming:
if (!$setup['App'] instanceof App)
{
throw new InvalidArgumentException('Not an App.');
}
With every class you then write all objects would be constructed upon initialisation. Also, with each construction of an object you would pass down the dependencies that are required (or let the default ones you provide) be instantiated. (You will notice when you forget to do this because you will have to rewrite your code to take out dependencies before you can test it.)
It seems like a lot of work, but the classes reflect the real world closer and testing becomes a breeze. You can also see the dependencies you have in your code easily in the constructor.
Well, if it was me, I would have the end goal of injecting the App dependency into any class (or class tree) that needs it. That way in testing or reusing the code you can inject whatever you want.
Note I said reuse there. That's because it's hard to re-use code that has static calls in it. That's because it's tied to the global state so you can't really "change" the state for a subrequest (or whatever you want to do).
Now, on to the question at hand. It appears that you have a legacy codebase, which will complicate things. The way I would approach it is as follows:
Create a non-static version of the app class (name it something different for now) that does nothing but proxy its get/set calls to the real app class. So, for example:
class AppProxy {
public function set($value) {
return App::set($value);
}
}
For now, all it has to do is proxy. Once we finish getting all the code talking to the proxy instead of the static app, we'll make it actually function. But until then, this will keep the application running. That way you can take your time implementing these steps and don't need to do it all in one big sweep.
Pick a main class (one that does a lot for the application, or is important) that you easily control the instantiation of. Preferably one that you instantiate in only one place (in the bootstrap is the easiest). Change that class to use Dependency Injection via the constructor to get the "appproxy".
a. Test this!
Pick another class tree to work on, based on what you think will be most important and easiest.
a. Test!!!
If you have more calls to App::, Go to #3
Change the existing App class to be non-static.
a. Test!!!!!!!!!!
Remove the AppProxy and replace with App in the dependency injectors. If you did it right, you should only have one place to change to make this switch.
Pat yourself on the back and go get a drink, cause you're done.
The reason that I segmented it out like this is that once a step is completed (any step), you can still ship working software. So this conversion could take literally months (depending on the size of your codebase) without interrupting business as usual...
Now, once you're done, you do get some significant benefits:
Easy to test since you can just create a new App object to inject (or mock it as needed).
Side effects are easier to see since the App object is required wherever it could be changed.
It's easier to componentize libraries this way since their side effects are localized/
It's easier to override (polymorphism) the core app class if it's injected than if it's static.
I could go on, but I think it's pretty easy to find resources on why statics are generally bad. So that's the approach I would use to migrate away from a static class to an instance...
If you don't want to have static functions but global access from everywhere WITHOUT passing the object to the places where it is actually needed then you pretty much can only use one thing:
A global variable
So you are not really better of doing that. But that is the only thing i can think of that would fulfill your requirements.
If you App object is something like an application config a first possible step would be to pass it to the objects that need it:
class Login {
public function __construct() {
$this->_login_seed = App::get('LOGIN_SEED');
self::$_ms = Database::getConnection();
}
changes into:
class Login {
public function __construct(App $app) {
$this->_login_seed = $app->get('LOGIN_SEED');
self::$_ms = Database::getConnection();
}

Alternative to regular PHP Class

Generally when creating a PHP class I would do something as such
class Foo
{
public function Foo(){}
public function RandomFunction(){};
}
global $foo;
$foo = new Foo();
$foo->RandomFunction();
I have noticed that on the web people are frowning upon the global vars for classes but without it I would not be able to access the class inside other functions.
Now an alternative to this would be using static classes as such:
class Foo
{
static public function RandomFunction(){}
}
Foo::RandomFunction();
My Question is this, is this the best alternative to global vars for classes? Or is there a better way to go about it all together?
In good OO practice, if a class needs to access an instance of another class, you pass object in as a parameter and then access it's properties and methods from there.
If you have a well designed object model the code should be relatively clean and logical, however if you aren't planning on creating a strict OO application, you probably shouldn't worry about your classes being in global scope or not.
Think of your object like a bicycle. You own your bicycle, and can loan it to whomever you wish. They can use it and return it to you, and you will be able to keep track of who did what to your bike, and when.
If your bike is generally available to anyone in the world, however, your job of monitoring and controlling access to it will become exponentially more difficult. You will be hard-pressed to keep track of who is using your bike, when they are using it, and how they are (ab)using it.
Passing your objects (rather than declaring them globally) allows you to maintain stricter controls on your object and the data it contains.

How to have a class spread across many source files?

I am currently working on a PHP project which includes extensive database usage. The basics are: I have a PDOFactory class which follows the Factory pattern and an abstract SQL class with static methods (just a container for those methods) which in turn talks to PDOFactory
As I said, the project involves extensive database usage, so the SQL class will contain numerous methods. However, they could be easily grouped, depending on what they deal with (i.e. session storage, user logging on/off, etc.). That would make the SQL class much easier to maintain and so on and forth. And here comes the big question: Can I have the source of the class contents spread across many files? There could be (at least) two possible solutions to this problem:
Multiple inheritance, i.e. having classes SQLSession, SQLUser, SQLblahblah and making the SQL class inherit all of them.
C++-like pre-processor* directives, i.e. #include SQLSession.php; or something like that.
I know there is no multiple inheritance in PHP, so that rules out option No. 1. Is option No. 2 even possible? Or does anybody know of better solutions to this problem?
*Or actually pre-pre-processor directives, since PHP is a pre-processor. :)
EDIT:
Here's an attempt to answer this question, based on Kalium's suggestion. It's a mess to read, but it works. However, I'm gonna stick with Bill's method as it's way cleaner.
class SQL {
private static $oInstance = false;
public static function getInstance()
{
if( self::$oInstance == false )
{
self::$oInstance = new self();
}
return self::$oInstance;
}
public $SESSION;
private function __construct()
{
$this->SESSION = new SESSION;
}
}
// this would be in another file
class SESSION {
public function printOne()
{
echo "One";
}
}
SQL::getInstance()->SESSION->printOne(); // outputs "One"
?>
I think you may be approaching this wrong. That's certainly not the best way to go about it. Try breaking the many functions into smaller utility classes and then using those to composite a larger class.
Don't use static methods, as it makes it hard to use something else than the SQL class
Use small classes, which have a single responsibility.
I think you should use the Builder pattern for your SQL instead of a motley container of static methods.
No, there is no multiple inheritance in PHP. Use delegation instead.
No, you can't include files to define methods of a class. You can only include files in contexts where code is executing, not in the middle of a class definition:
<?php
include("define-functions.php"); // OK
class Foo
{
include("define-methods.php"); // ERROR
function foo()
{
include("method-body.php"); // OK
}
}
PHP Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION
in foo.php on line 7
Re your comment:
Since you're committed to using only static methods, why bother with a class at all? Just define functions in the global scope. Then you can include() as many as you want:
<?php
include("SQLSession.php");
include("SQLUser.php");
include("SQLblahblah.php");
SQLSession.php:
<?php
function SQLSessionStart()
{
...
}
function SQLSessionEnd()
{
...
}
You don't have access to static class member data with this solution, but you can just use global variables.
to me, it sounds like you're trying to create a monolithic chunk of code, which is the exact opposite of class based OO code - I'd recommend following the DAO blueprint of the Java core patterns, and implementing it in PHP for what you want to do :) that should cover all you're questions

PHP Object Oriented Web Application

I have a class called "Layout" for the layout of the page, another class called "User" for the user.
Every page I create, I instantiate a new Layout.
When a user logs in, there is a new User instantiated.
How do I get an instance of the layout class to know about the instantiated user? I could also save the entire instance of the User in a session variable. I assume that's a bad idea though. What are the best practices for this?
class User
{
var $userid;
var $email;
var $username;
function User($user)
{
$this->userid = $this->getUid($user);
$this->email = $this->getEmail($user);
$this->username = $user;
}
function getUid($u)
{
...
}
function getEmail($u)
{
...
}
}
class Layout
{
var $var1;
var $var2;
var $var3;
function Layout()
{
//defaults...
}
function function1()
{
echo "something";
}
function function2()
{
echo "some other stuff";
}
function function3()
{
echo "something else";
}
}
so in index.php, for example, i would do the following:
include "user.php"
include "layout.php"
$homelayout = new Layout();
$homelayout->function1();
$homelayout->function2();
$homelayout->function3();
now let's say that in login.php someone logged in:
include "layout.php"
include "user.php"
if(userAuthSuccess)
{
$currentUser = new User($_POST['username']);
}
what is the best way to gain access to $currentUser and it's member variables such as $currentUser->email, etc. from all php files from here on out, as long as the user hasn't logged out?
I think the best remedy to the solution stated above is going for a concept called Dependency Injection, whereby you write an extra class, that will inject the dependency (An Object in this case) to the requesting class. Most of the modern developers will adhere to using this technique of injecting dependencies into their applications as this will enable:
Loosely coupled programs - As the dependency is injected by a third class, there is no need to hard code the dependency in the logic of the program.
Maintainable code - This is that feature of the OOP paradigm that allures the most. This is especially true when referring to large scale programs.
Memory Management - As a developer, you are free to manage the memory to your specification requirements.
Since there will be only one User for every request and thus for every run of your program, this would be a case to make "User" a Singleton class as described here:
http://php.net/manual/en/language.oop5.patterns.php
That would provide the one way for other classes to refer to the current user without the chance of accessing the wrong instance since there is only one.
DISCLAIMER:
Yes, I know that Singeltons are often used at the wrong places for the wrong purpose and some people tend to blame this problem on the pattern instead of the people who misused it for some smelly code.
This however is a perfectly good use case for the Singelton pattern.
"Globalizing" something by putting it in a session variable or cookie for the sole purpose of globalizing it is a very bad habit to get into, and it leads to tightly coupled libraries that rely on an arbitrary variable being set outside the class. Session variables in general are good to stay away from for other reasons, too.
The best way to get a variable into any class is to pass it as an argument. Do you have a method in your Layout class that renders (outputs) it? You may want to add a $data argument to that method that takes an associative array of data usable in the layout.
I'd personally use a registry class (Singleton) and register the user there for the Layout to access. That way, you only need to pass an instance of the registry to the Layout.
The User class is not integral to the Layout's construction - since it should only be concerned with the Layout, so I wouldn't pass that in the constructor.
Another method would be to use a Controller to orchestrate these interactions between Views and Models. Whenever a new Controller is created, buffer it's output. Then, at render time, unbuffer the contents and assign them to properties (or a property array) of the view, which can then render them. You probably don't need an actual Model class to be passed to the View/Layout - just it's output.
Use a registry pattern. No need to make it a singleton, everyone is throwing that word around.
include "layout.php"
include "user.php"
if(userAuthSuccess)
{
$data['currentUser'] = new User($_POST['username']);
}
$data['nav'] = new nav('home');
$homelayout = new Layout( $data );
Now $homelayout can access $data (which contains all the variables you put into it) via the data array.

Categories