Call a Function from extended Class - php

From extended, I want call a parent function like this
file 1 > Main Class:
class CheckoutProcessCore implements Interface
{
public function __construct(
Context $context,
CheckoutSession $checkoutSession
) {
$this->context = $context;
$this->smarty = $this->context->smarty;
$this->checkoutSession = $checkoutSession;
}
public function getSteps()
{
return $this->steps;
}
}
file 2 > Extended Class:
class Basket extends CheckoutProcessCore
{
protected static $basket_pid = null;
function __construct() {
parent::__construct();
}
public static function test() {
$step = parent::getSteps(); <-- the Problem!
[ ... ]
}
}
How can I call getSteps from test without any errors ?
What's wrong in my Code ?
Thank you

I'm not so sure if this might help/solve your problem. However,
You might have forgotten adding your files on the top of pages that might be required to do so, if you are not using autholoader/composer:
require_once('/path/to/CheckoutProcessCore.php');
require_once('/path/to/Basket.php');
Also, you probably are not allowed to use Interface as an identifier, for which you may look into this post, which says Interface is a reserved word. You cannot most likely use other variances of Interface, such as (interface, iNterface, etc.) as an identifier.
require_once('/path/to/InterfaceSomeAddedNameThatYouWish.php');
Then, you might consider modifying:
class CheckoutProcessCore implements InterfaceSomeAddedNameThatYouWish
{
public function __construct(
Context $context,
CheckoutSession $checkoutSession
) {
$this->context = $context;
$this->smarty = $this->context->smarty;
$this->checkoutSession = $checkoutSession;
}
public function getSteps()
{
return $this->steps;
}
}

Related

Using a factory method with Inversion of control when class type is not known at runtime

I have a question about IOC and when I don't know the class to be instantiated at run-time. For example, I have a few types of View classes. (HtmlView, CsvView, PDFView, etc ) that implement my view interface. The type of view class that I need is determined by user input ( a string in the DB ). I am leaning to using a ViewFactory class that has a make method, the problem is that this will be hiding the View dependency because I only need a ViewFactory.
class ViewFactory{
public function make($viewType){
if($viewType == 'html'){
$view = new HtmlView();
}
// ...
return $view
}
}
class ReportGenerator{
public function constructor(Array $data, ViewFactory $viewFactory, String $viewType ){
$this->data = $data;
$this->view = $viewFactory($viewType);
}
public function generate(){
return $this->view->render($this->data)
}
}
It seems to me unclear that ReportGenerator depends on a base ViewInterface. Is there a better way, without using a static method.
interface ViewInterface {
public function render();
}
class HtmlView implements ViewInterface {
const HTML_VIEW = 'html';
public function render() {
// TODO: Implement render() method.
}
}
class AnotherView implements ViewInterface {
const ANOTHER_VIEW = 'another';
public function render() {
// TODO: Implement render() method.
}
}
class ViewFactory {
public static function make($viewType) { // this could also be static
// or use a construct, whichever strikes your fancy
if ('html' == $viewType) { // fan of Yoda metod, I am
$view = new HtmlView();
}
// ...
return $view;
}
}
class ReportGenerator {
private $data;
private $view;
public function constructor(array $data, ViewInterface $view) {
$this->data = $data;
$this->view = $view;
}
public function generate() {
return $this->view->render($this->data);
}
}
$view = ViewFactory::make(HtmlView::HTML_VIEW);
$report = new ReportGenerator([], $view);
Instead of letting the ReportGenerator deal with anything view related, which it must never do, simply pass in the already created view.
The view itself should be created outside of ReportGenerator(or any other class for that matter - except the ViewFactory).
In the ViewFactory you can always add other methods to deal with the logic of creating new views.

Learning PHP Interfaces - Error In Code

I'm following along with some learning material on PHP and am now into abstract classes and methods as well as interfaces. While implementing interfaces I've encountered an error on first run-through. It happens while the classes and interfaces are being defined. I apologize in advance for the size of the code sample but I'd like to be circumspect.
The error I receive is:
'Fatal error: Declaration of DinnerMenu::setDinnerPortion() must be compatible with DinnerPortion::setDinnerPortion() in ... Menu.php on line 85'.
Menu.php follows:
<?php
abstract class Menu { // can't be instanciated, only extended from
private $_menuid,
$_menuitemid,
$_menuname,
$_description;
public function setMenuID($menuid) {$this->_menuid = $menuid;}
public function getMenuID() {return $this->_menuid;}
public function setMenuItemID($menuitemid) {$this->_menuitemid = $menuitemid;}
public function getMenuItemID() {return $this->_menuitemid;}
public function setMenuName($menuname) {$this->__menuname = $menuname;}
public function getMenuName() {return $this->_menuname;}
public function setDescription($description) {$this->_description = $description;}
public function getDescription() {return $this->_description;}
}
class MenuItem {
private $_menuitemid,
$_itemname,
$_description,
$_price,
$_servingsize,
$_picture;
public function setID($menuitemid) {$this->_menuitemid = $menuitemid;}
public function getID() {return $this->_menuitemid;}
public function setItemName($itemname) {$this->_itemname = $itemname;}
public function getItemName() {return $this->_itemname;}
public function setDescription($description) {$this->_description = $description;}
public function getDescription() {return $this->_description;}
public function setPrice($price) {$this->_price = $price;}
public function getPrice() {return $this->_price;}
public function setServingSize($servingsize) {$this->_servingsize = $servingsize;}
public function getServingSize() {return $this->_servingsize;}
public function setPicture($picture) {$this->_picture = $picture;}
public function getPicture() {return $this->_picture;}
}
class MainMenu extends Menu {
}
class DrinkMenu extends Menu {
}
class LunchMenu extends Menu {
}
final class KidsMenu extends Menu { // final keyword stops inheritance: cannot have sub-classes or child classes, cannot be overridden
}
final class DessertMenu extends Menu {
}
interface DinnerPortion {
public function setDinnerPortion();
}
interface DinnerPrices {
public function setDinnerPrices();
}
interface HappyHourDrinkPrices {
public function setHappyHourDrinkPrices();
}
final class DinnerMenu extends LunchMenu implements DinnerPortion, DinnerPrices {
public function setDinnerPortion($menuitemObject) {
$adjusted_servingsize = 1;
$base_servingsize = $menuitemObject->getServingSize();
// dinner portion 50% bigger than lunch portion
$adjusted_servingsize = $base_servingsize * 1.5;
return $adjusted_servingsize;
}
public function setDinnerPrices($menuitemObject) {
$adjusted_price = 1;
$base_price = $menuitemObject->getPrice();
// dinner price 25% more than lunch price
$adjusted_price = $base_price * 1.25;
return $adjusted_price;
}
}
final class HappyHourMenu extends DrinkMenu implements HappyHourDrinkPrices {
public function setHappyHourDrinkPRices($drinkObject) {
$adjusted_price = 1;
$base_price = $drinkObject->getPrice();
// happy hour drink prices 30% less than regular prices
$adjusted_price = $base_price * 0.7;
return $adjusted_price;
}
}
?>
setDinnerPortion in the interface doesn't have an argument, while the same method in the class DinnerMenu (which implements the interface) has the argument $menuitemObject.
An interface describes rules that a class must obey. In this case it defines that the class needs to implement this method without arguments.
If you want to use interfaces with their methods, you have to take over the methods which are described in the interface.
From your interface ;
public function setDinnerPortion($menuitemObject)
The above method requires an argument while the method in your class which implements the interface doesn't have it
public function setDinnerPortion()
Solution : add an argument.
in your class the signature is :
public function setDinnerPortion($menuitemObject)
although in your interface the function signature is :
public function setDinnerPortion();
These function signatures must be the same !

PHP Magic methods

My question revolves arround magic methods.
This is a little example:
$context = new Context('Entities.xml');
$user_array = $context->Users;
$user = $context->Users->find(array('name' => 'John Smith'));
The second line returns an array with all user objects in it. The third line returns only the User object of the user called John Smith.
I wondered if this would be possible, the tricky part is that I don't know the properties of the Context class. They are generated from an xml file the user supplies upon instantiation and are accessable through magic getters and setters.
Context example(not complete, just to give an idea):
class Context {
private $path, $entities;
public function __construct($path) {
$this->path = $path;
}
public function __get($name) {
return $entities[$name];
}
public function __set($name, $arg) {
$entities[$name] = $arg;
}
}
Because I really needed a solution I implemented the following solution.
The getters of the Context class return a ResultLayer class that handles the results.
Example:
class ResultLayer implements IteratorAggregate {
public $data = array();
private $entity, $context;
public function __construct($context, $entity) {
$this->context = $context;
$this->entity = $entity;
}
public function getIterator() {
return new ArrayIterator($this->data);
}
public function get($index) {
return $this->data[$index];
}
public function toArray() {
return $this->data;
}
public function find($properties) {
return $this->context->getEntity($this->entity, $properties);
}
}
I have implemented the IteratorAggregate interface so that you can use a foreach loop to for example go through $Context->Users this makes the code more readable.
If anyone has a better approach, I'm still open to it. Any help is much appreciated!

php enforce type of extending class

Is there any way in php to make sure that a class can be extended by one and only one class?
I have some code that illustrates what I'm trying to do, basically I have a DB manager class and a DB query class that is extended by the manager class. What I'd like to do is make sure that the DB query class can only be used by the DB manager class.
The code below works, but it seems very rough. In the code I delcare the query class abstract with a single abstract function that checks the classname, or I could simply declare all of the Manager functions as abstract in the query class (which seems hacky). If there is a simpler way to do this than my code below that would be very useful...
abstract class DB_Query {
private static $HOST = 'localhost';
private static $USERNAME = 'guest';
private static $PASSWORD = 'password';
private static $DATABASE = 'APP';
//////////
/* USING ABSTRACT FUNCTION HERE TO ENFORCE CHILD TYPE */
abstract function isDB();
/* OR USING ALTERNATE ABSTRACT TO ENFORE CHILD TYPE */
abstract function connect();
abstract function findConnection();
abstract function getParamArray();
//////////
private function __construct() { return $this->Connect(); }
public function Read($sql) { //implementation here }
public function Query($sql) { //implementation here }
public function Fetch($res, $type='row', $single='true') { //implementation here }
}
class DB extends DB_Query {
public $connections = array();
public static $instance;
public function isDB() {
if (get_parent_class() === 'Database' && get_class($this)!=='DB') {
throw new \Exception('This class can\'t extend the Database class');
}
}
public function connect($host=null,$user=null,$pass=null,$db=null) { //implementation here }
function findConnection($user, $password=null) { //implementation here }
public function getParamArray($param) {}
public function threadList() {}
public function getThread($threadId=null) {}
public static function Singleton() { //implementation here }
private function __construct() { //implementation here }
}
I would go after marking the constructor of DB_Query as final and implementing it the way that it checks the instance and fires some exception. Something like this
class Base {
final function __construct() {
if (!$this instanceof Base && !$this instanceof TheChosenOne) {
throw new RuntimeException("Only TheChosenOne can inherit Base");
}
/**
* use this function as constructor
*/
$this->__internal_base_construct();
}
protected function __internal_base_construct() {
// constructor code
}
}
But your problem is rather strange and kind of breaking the idea of OOP in several ways. Just combine it into a single class and use final class directive.
http://php.net/manual/en/language.oop5.final.php
class Database_Query extends Database {
public static $instance;
public function Query($sql) {}
public function Fetch($res, $type='row', $single='true') {}
public static function Singleton() {}
private function __construct() {
$this->link = $this->connect()->find('guest')->getLink();
}
}

Faking method attributes in PHP?

Is it possible to use the equivalent for .NET method attributes in PHP, or in some way simulate these?
Context
We have an in-house URL routing class that we like a lot. The way it works today is that we first have to register all the routes with a central route manager, like so:
$oRouteManager->RegisterRoute('admin/test/', array('CAdmin', 'SomeMethod'));
$oRouteManager->RegisterRoute('admin/foo/', array('CAdmin', 'SomeOtherMethod'));
$oRouteManager->RegisterRoute('test/', array('CTest', 'SomeMethod'));
Whenever a route is encountered, the callback method (in the cases above they are static class methods) is called. However, this separates the route from the method, at least in code.
I am looking for some method to put the route closer to the method, as you could have done in C#:
<Route Path="admin/test/">
public static void SomeMethod() { /* implementation */ }
My options as I see them now, are either to create some sort of phpDoc extension that allows me to something like this:
/**
* #route admin/test/
*/
public static function SomeMethod() { /* implementation */ }
But that would require writing/reusing a parser for phpDoc, and will most likely be rather slow.
The other option would be to separate each route into it's own class, and have methods like the following:
class CAdminTest extends CRoute
{
public static function Invoke() { /* implementation */ }
public static function GetRoute() { return "admin/test/"; }
}
However, this would still require registering every single class, and there would be a great number of classes like this (not to mention the amount of extra code).
So what are my options here? What would be the best way to keep the route close to the method it invokes?
This is how I ended up solving this. The article provided by Kevin was a huge help. By using ReflectionClass and ReflectionMethod::getDocComment, I can walk through the phpDoc comments very easily. A small regular expression finds any #route, and is registered to the method.
Reflection is not that quick (in our case, about 2,5 times as slow as having hard-coded calls to RegiserRoute in a separate function), and since we have a lot of routes, we had to cache the finished list of routes in Memcached, so reflection is unnecessary on every page load. In total we ended up going from taking 7ms to register the routes to 1,7ms on average when cached (reflection on every page load used 18ms on average.
The code to do this, which can be overridden in a subclass if you need manual registration, is as follows:
public static function RegisterRoutes()
{
$sClass = get_called_class(); // unavailable in PHP < 5.3.0
$rflClass = new ReflectionClass($sClass);
foreach ($rflClass->getMethods() as $rflMethod)
{
$sComment = $rflMethod->getDocComment();
if (preg_match_all('%^\s*\*\s*#route\s+(?P<route>/?(?:[a-z0-9]+/?)+)\s*$%im', $sComment, $result, PREG_PATTERN_ORDER))
{
foreach ($result[1] as $sRoute)
{
$sMethod = $rflMethod->GetName();
$oRouteManager->RegisterRoute($sRoute, array($sClass, $sMethod));
}
}
}
}
Thanks to everyone for pointing me in the right direction, there were lots of good suggestions here! We went with this approach simply because it allows us to keep the route close to the code it invokes:
class CSomeRoutable extends CRoutable
{
/**
* #route /foo/bar
* #route /for/baz
*/
public static function SomeRoute($SomeUnsafeParameter)
{
// this is accessible through two different routes
echo (int)$SomeUnsafeParameter;
}
}
Using PHP 5.3, you could use closures or "Anonymous functions" to tie the code to the route.
For example:
<?php
class Router
{
protected $routes;
public function __construct(){
$this->routes = array();
}
public function RegisterRoute($route, $callback) {
$this->routes[$route] = $callback;
}
public function CallRoute($route)
{
if(array_key_exists($route, $this->routes)) {
$this->routes[$route]();
}
}
}
$router = new Router();
$router->RegisterRoute('admin/test/', function() {
echo "Somebody called the Admin Test thingie!";
});
$router->CallRoute('admin/test/');
// Outputs: Somebody called the Admin Test thingie!
?>
Here's a method which may suit your needs. Each class that contains routes must implement an interface and then later loop through all defined classes which implement that interface to collect a list of routes. The interface contains a single method which expects an array of UrlRoute objects to be returned. These are then registered using your existing URL routing class.
Edit: I was just thinking, the UrlRoute class should probably also contain a field for ClassName. Then $oRouteManager->RegisterRoute($urlRoute->route, array($className, $urlRoute->method)) could be simplified to $oRouteManager->RegisterRoute($urlRoute). However, this would require a change to your existing framework...
interface IUrlRoute
{
public static function GetRoutes();
}
class UrlRoute
{
var $route;
var $method;
public function __construct($route, $method)
{
$this->route = $route;
$this->method = $method;
}
}
class Page1 implements IUrlRoute
{
public static function GetRoutes()
{
return array(
new UrlRoute('page1/test/', 'test')
);
}
public function test()
{
}
}
class Page2 implements IUrlRoute
{
public static function GetRoutes()
{
return array(
new UrlRoute('page2/someroute/', 'test3'),
new UrlRoute('page2/anotherpage/', 'anotherpage')
);
}
public function test3()
{
}
public function anotherpage()
{
}
}
$classes = get_declared_classes();
foreach($classes as $className)
{
$c = new ReflectionClass($className);
if( $c->implementsInterface('IUrlRoute') )
{
$fnRoute = $c->getMethod('GetRoutes');
$listRoutes = $fnRoute->invoke(null);
foreach($listRoutes as $urlRoute)
{
$oRouteManager->RegisterRoute($urlRoute->route, array($className, $urlRoute->method));
}
}
}
I'd use a combination of interfaces and a singleton class to register routes on the fly.
I would use a convention of naming the router classes like FirstRouter, SecondRouter and so on. This would enable this to work:
foreach (get_declared_classes() as $class) {
if (preg_match('/Router$/',$class)) {
new $class;
}
}
That would register all declared classes with my router manager.
This is the code to call the route method
$rm = routemgr::getInstance()->route('test/test');
A router method would look like this
static public function testRoute() {
if (self::$register) {
return 'test/test'; // path
}
echo "testRoute\n";
}
The interfaces
interface getroutes {
public function getRoutes();
}
interface router extends getroutes {
public function route($path);
public function match($path);
}
interface routes {
public function getPath();
public function getMethod();
}
And this is my definition av a route
class route implements routes {
public function getPath() {
return $this->path;
}
public function setPath($path) {
$this->path = $path;
}
public function getMethod() {
return $this->method;
}
public function setMethod($class,$method) {
$this->method = array($class,$method);
return $this;
}
public function __construct($path,$method) {
$this->path = $path;
$this->method = $method;
}
}
The Router manager
class routemgr implements router {
private $routes;
static private $instance;
private function __construct() {
}
static public function getInstance() {
if (!(self::$instance instanceof routemgr)) {
self::$instance = new routemgr();
}
return self::$instance;
}
public function addRoute($object) {
$this->routes[] = $object;
}
public function route($path) {
foreach ($this->routes as $router) {
if ($router->match($path)) {
$router->route($path);
}
}
}
public function match($path) {
foreach ($this->routes as $router) {
if ($router->match($path)) {
return true;
}
}
}
public function getRoutes() {
foreach ($this->routes as $router) {
foreach ($router->getRoutes() as $route) {
$total[] = $route;
}
}
return $total;
}
}
And the self register super class
class selfregister implements router {
private $routes;
static protected $register = true;
public function getRoutes() {
return $this->routes;
}
public function __construct() {
self::$register = true;
foreach (get_class_methods(get_class($this)) as $name) {
if (preg_match('/Route$/',$name)) {
$path = call_user_method($name, $this);
if ($path) {
$this->routes[] = new route($path,array(get_class($this),$name));
}
}
}
self::$register = false;
routemgr::getInstance()->addRoute($this);
}
public function route($path) {
foreach ($this->routes as $route) {
if ($route->getPath() == $path) {
call_user_func($route->getMethod());
}
}
}
public function match($path) {
foreach ($this->routes as $route) {
if ($route->getPath() == $path) {
return true;
}
}
}
}
And finally the self registering router class
class aRouter extends selfregister {
static public function testRoute() {
if (self::$register) {
return 'test/test';
}
echo "testRoute\n";
}
static public function test2Route() {
if (self::$register) {
return 'test2/test';
}
echo "test2Route\n";
}
}
the closest you can put your path to the function definition (IMHO) is right before the class definition. so you would have
$oRouteManager->RegisterRoute('test/', array('CTest', 'SomeMethod'));
class CTest {
public static function SomeMethod() {}
}
and
$oRouteManager->RegisterRoute('admin/test/', array('CAdmin', 'SomeMethod'));
$oRouteManager->RegisterRoute('admin/foo/', array('CAdmin', 'SomeOtherMethod'));
class CAdmin {
public static function SomeMethod() {}
public static function SomeOtherMethod() {}
}
There is a proposal for this, it was declined. See the rfc here:
Attributes RFC at php.net
My solution to this desire is something like this:
abstract class MyAttributableBase{
protected static $_methodAttributes=[];
public static function getMethodAtributes(string $method):?array{
if( isset(self::$_methodAttributes[$method])){
return self::$_methodAttributes[$method];
}
return null;
}
protected static function setMethodAttributes(string $method, array $attrs):void{
self::$_methodAttributes[$method] = $attrs;
}
}
class MyController extends MyAttributableBase{
protected static function getMethodAtributes(string $method):?array{
switch( $method ){
case 'myAction':
return ['attrOne'=>'value1'];
default:
return parent::getMethodAttributes($method);
}
}
}
Usage:
$c = new MyController();
print $c::getMethodAttributes('myAction')['attrOne'];
You can of course use it from within a base class method to do "routing" stuff in this case, or from a routing class that operates on "MyAttributableBase" objects, or anywhere else you would want to inspect this attached metadata for any purpose. I prefer this "in-code" solution to using phpDoc. Note I didn't attempt to test this exact code but it is mentally copied from a working solution. If it doesn't compile for some small reason it should be easy to fix and use. I have not figured out a way to cleanly put the attributes near the method definition. Using this implementation in the base you COULD set the attributes within the method (myAction in this case) as the first code to execute, but it would not be a static attribute, it would get reset at each invocation. You could add code to additionally ensure it is only set once but that's just extra code to execute and maybe is not better. Overriding the get method allows you to set the info once and refer to it once, even though it's not that close to the method definition. Keeping the static array in the base does allow some flexibility if there are cases for adding or changing metadata at runtime. I could be possible to use something like phpDoc and a static constructor to parse that when the first class is created to populate the static metadata array. I haven't found a solution that is awesome but the one I'm using is adequate.

Categories