Reusing code in php modules without sharing global namespace - php

I can't seem to figure out to achieve the following result.
Important: this should work down to php 5.3
Ok, so imagine a situation: you develop a number of php modules, for example WordPress plugins, that are to be run on single setup but do not communicate or know about each other. But some (quite large) parts of codebase are the same and can be reused. How can I achieve the result, when all my modules have "inside of them" this shared library, scoped to each module and not causing conflicts in global space?
For example, see the following:
main.php (some host app, like WordPress)
<?php
require('plugins/first-module/first.php');
require('plugins/second-module/second.php');
$first = new Project1\App();
$first->go();
$second = new Project2\App();
$second->go();
?>
first.php (first module)
<?php
namespace Project1;
require('shared.php');
use CoreLib\Util\Logger\Log;
class App {
public function go() {
$logger = new Log();
$logger->say();
}
}
second.php (second module)
<?php
namespace Project2;
require('shared.php');
use CoreLib\Util\Logger\Log;
class App {
public function go() {
$logger = new Log();
$logger->say();
}
}
shared.php (shared lib)
<?php
namespace CoreLib\Util\Logger;
class Log {
public function say() {
echo 'It works!';
}
}
Right now I have an error, obviously, because of re-declaring Log class.
Any ideas?

Related

Init another class in construct method?

I am looking into trying to simplify my PHP code some more, and I have yet to find an answer with this methodology one of my team members are using. Nor, have I ever saw this done before anywhere on the web.
Here is the code example from our web application which he is working on with me.
<?php
class ArticlesHandler {
public function __construct() {
require 'Articles.php';
$articles = new Articles;
}
}
?>
Is this proper to init one class within another class?
For me, this just seems not proper standard to init classes to work together.
Yes and no. It works, but this particular code can lead to a number of problems.
You should be using require_once instead of require to avoid possible errors of including the same file twice. As it is this code here will bring your app to a complete stop:
new ArticlesHandler;
new ArticlesHandler;
This creates a hard coupling to the Articles class. You should probably rather be using dependency injection and pass an instance of Article to the constructor of ArticlesHandler. See How Not To Kill Your Testability Using Statics.
Yes, it is proper and normal to call constructors in a constructor. There is nothing weird/bad about it.
This is what I normally do.
class Repository {
protected $_models = array();
public function getModel($model, array $params = array()){
require_once $model.'.php'; //Replace this with an autoloader
if(empty($this->_models[$model])){
if(!empty($params)){
$this->_models[$model] = new $model($params);
} else {
$this->_models[$model] = new $model();
}
}
return $this->_models[$model];
}
}
And call the other class like this.
class ArticlesHandler extends Repository {
public function __construct() {
$articles = $this->getModel('Articles');
}
}
it seem's right.
For me, this just seems not proper standard to init classes to work together.
you can extend Articles class if you want to use Articles class inside the ArticlesHandler

Getting a 500 internal server error when implementing interface

I'm writing some dummy code to learn some design patterns. Therefore I made a class Duck.php that implements FlyBehavior. When I call the index.php, I see a blank page, and the console tells me, there is a 500 Internal Server Error. If I outcomment implenets FlyBehavior, the error disappears. So I guess I'm missing something about how to correctly implement an interface.
Thank you!
PHP 5.4.10
Duck.php
<?php
class Duck implements FlyBehavior
{
public function flyWithWings(){
echo 'foo';
}
}
FlyBehavior.php
<?php
interface FlyBehavior {
public function flyWithWings();
}
index.php
<?php
ini_set('error_reporting', E_ALL);
include 'Duck.php';
$duck = new Duck();
echo '<br>Test';
Your problem is that you didn't include the interface in the class that implements it, you can do that by require_once
Or an alternate to this is to use dependency management , for example check composer
<?php
require_once('FlyBehaviour.php');
class Duck implements FlyBehavior
{
public function flyWithWings(){
echo 'foo';
}
}
?>
If you hate having to require/include all the class library every time manually - like I do; perhaps __autoload may be of interest to you:
http://www.php.net/manual/en/function.autoload.php
Setup your scripts like this:
/ index.php
/ libs / FlyBehavior.php
/ libs / Duck.php
I.e. place all your classes in a folder called libs and then setup audoloader on index.php
So, your index.php will look like this:
<?php
// Constants
define('CWD', getcwd());
// Register Autoloader
if (!function_exists('classAutoLoader')) {
function classAutoLoader($class) {
$classFile = CWD .'/libs/'. $class .'.php';
if (is_file($classFile) && !class_exists($class))
require_once $classFile;
}
}
spl_autoload_register('classAutoLoader');
// Rest if your script
ini_set('error_reporting', E_ALL);
ini_set('display_error', 'On');
// Test
$duck = new Duck();
$duck->flyWithWings();
?>
Now, all the required classes are automatically loaded (when you instantiate them for the first time) - meaning you don't have to require any of the class files manually in your script.
Try it out; will save you tons of time :)

Phalcon: global keyword doesn't work inside Index Controller

This post may be long and messy but oh well... So i have my website in raw PHP
My original file structure:
/Index.php
/Users.php
/Smarty.class.php
/db.php
/Stats.php
/css/
/js/
Now i want to "port" each index file into phalcon controllers, like this:
/Controllers/IndexController.php
/Controllers/UsersController.php
/Smarty.class.php
/db.php
/css/
/js/
The thing is that global keyword doesnt work inside IndexController.php:
class IndexController extends \Phalcon\Mvc\Controller
{
include "/db.php"; // $db is initialized there
include_once ("Smarty.class.php");
$main_smarty = new Smarty;
public function indexAction()
{
function doSearch($limit) {
global $db, $current_user, $main_smarty; // db and smarty objects
$db->get_results("// my query"");
$search_clause = $this->get_search_clause();
$main_smarty->assign('search', $this->searchTerm);
}
}
}
Fatal error: Call to a member function get_results() on a non-object
But it works fine in my original code, without Phalcon.
include "/db.php";
function doSearch($limit) {
global $db, $current_user, $main_smarty;
$search_clause = $this->get_search_clause();
$main_smarty->assign('search', $this->searchTerm);
My bootstrap (Index.php) File:
try {
//Register an autoloader
$loader = new \Phalcon\Loader();
$loader->registerDirs(array(
'Controllers/',
))->register();
// DI
$di = new Phalcon\DI\FactoryDefault();
// View component
$di->set('view', function(){
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('/');
return $view;
});
$application = new \Phalcon\Mvc\Application($di);
echo $application->handle()->getContent();
} catch(\Phalcon\Exception $e) {
echo "PhalconException: ", $e->getMessage();
}
Woah there, hold on a second..
It is great that you've identified the code you've written could be improved, but improvement doesn't just mean "moving everything from one place to another".
What you have the chance to do is to rethink how you've done things, and move into a "more structured" (in my opinion..) way of working.
Assuming you have successfully got Phalcon setup, I'd suggest reading through the first tutorial. This really is a great resource.
The MVC architecture is something a lot of sites run with nowadays, and if you aren't familiar with it, this link might help you out.
It is difficult to provide a direct answer to your question, as I think after a bit of reading everything will become clearer.
In your case, it sounds like it might be good to have this Smarty class as a service, that can be registered with Phalcon that can then be dependency injected.
Have a go/read, and let me/us know how it goes for you.

replicating a feature in zend

I have been pouring over Zend_View and the various classes and interfaces that make up the view. One thing I am attempting to replicate in a project that does not use zend in any way shape or form is the:
$this->view->variable = 'Hello world';
that you can set in a controller and then do:
echo $this->view->variable;
My ultimate goal is to do something like:
$this->variable = new SomeClass
and then else where, in a view specifically, do:
$this->variable->someMethod();
My question is:
How would I replicate what zend does to do something simmilar with out using global variables?
How is zend able to do something like $this->view with out ever instantiating or saying what view is?
this would help me understand how, variables are passed around or objects are passed from the logic to the view and how php allows for something like $this->view to work when in a view or not.
note: this is not a Zend specific question and "use zend" is not the answer. I am looking to replicate a specific feature. My project does not in any way use or affiliate with zend.
I don't know why exactly you want to achieve this, but as a super simple setup (which is by no means suited to be the basis of an MVC framework) you can look at this:
<?php
class Controller
{
private $view = null;
public function __construct()
{
$this->view = new View();
$this->view->someVar = "foobar";
}
public function render()
{
include "view.php";
}
}
class View
{
}
$controller = new Controller();
$controller->render();
And then, in view.php, you can do:
<?php
echo $this->view->someVar;
Beware: This code only shows HOW it's possible to achieve such a construct, it does not anything useful at all ;).
It's actually pretty simple. When you use include, require, eval et al., the loaded code is brought in to the current scope. So if you have a template file
template.php
<span><?=$this->view->somevar?></span>
Controller.php
<?php
class Controller
{
private $view;
public function doSomething()
{
$this->view->somevar = 'Hello World';
include 'template.php';
}
}
index.php
<?php
require 'Controller.php';
$oC = new Controller();
$oC->doSomething();
Blamo.., template.php is able to call $this->view->somevar as it is treated as part of Controller.php. Running php index.php on the CLI produces
<span>Hello World</span>
To elaborate a tiny bit, if $this->view inside of Controller.php were a class you've defined rather than a simple instance of stdClass as in the above demonstration, and it had a function someMethod, you could call $this->view->someMethod() from template.php just the same.

Instantiate plugins efficiently with observer pattern (php)

I'm implementing the observer pattern to all plugins to interact with my web app. Now, I want to make installing plugins painless (i.e just putting files into a plugin folder) like most web apps do.
For example:
A plugin with the name "Awesome Stuff" that executes code based on events that occur in the Auth class and the Content class would include the following files in the "/plugin" directory.
AwesomeStuffAuth.php
AwesomeStuffContent.php
I've got a solution that's working, but I'm afraid it's not efficient, as it has to cycle through ALL the declared classes before it actually finds what it's looking for.
function __construct() {
//Get files in plugin directory that work on Auth
foreach (glob("plugins/*AuthPlugin.php") as $filename) {
//Include'em
include_once($filename);
}
//Get all declared classes
foreach (get_declared_classes() as $class){
if (substr($class,-10)=='AuthPlugin'){
$obj = new $class;
$this->addObserver($obj);
}
}
}
This is the __construct() method that I use with the Auth class, and other classes would have similar methods.
Is this an efficient way of doing this? Is it worth me connecting to a database to avoid cycling through all the declared classes? How about flat file?
Thanks so much for taking a look at this.
A possible solution would be to use __autoload to catch the moment where the plugin is requested and add it to a list of observers at this moment, based on naming conventions:
function __autoload($class) {
include_once 'plugins/' . $class . '.php';
$observable = substr($class,-16); # E.g. 'Auth'
$observable::addObserverClass($class);
}
then in the Auth class:
class Observable {
static $observer_classes = array();
static function addObserverClass($class) {
self::$observer_classes[] = $class;
}
static function addObservers($self) {
foreach(self::$observer_classes as $class) {
$self->addObserver($class);
}
}
function addObserver($class) {
# Add the Observer.
}
}
class Auth extends Observable {
function __construct() {
self::addObservers($self);
}
}
Haven't tested the code, but you should get the idea. It eliminates both the need to glob and the need to iterate over every declared class each time a class is created.

Categories