Is it necessary to cache objects? - php

For a project I have some objects, one method is to load the parent entity.
So I call the method like this:
$this->getDetails()->getEntity();
So the code of getEntity is:
public function getEntity()
{
if (isset($this->entity)) {
return $this->entity;
} else {
$mapper = new Crm_Mapper_Entity();
return $this->entity = $mapper->find($this->customerId);
}
}
Is it necessary to load the entity into the attribute? Because when I want to load it on another place it shouldnt be calling the mapper again.
Or is it that when it's loaded, the object is already in memory and I don't need to put it into the attribute?
Thanks

use singleton pattern like this:
class MyStatic{
private static $instance;
private __construct(){}
public static getInstance(){
if (!empty(MyStatic::$instance;)) {
return MyStatic::$instance;
} else {
$mapper = new Crm_Mapper_Entity();
$thisMyStatic::$instance = $mapper->find($this->customerId);
return $thisMyStatic::$instance;
}
}
}

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.

return type of container from subclass

I have a PHP library which I don't want to edit, and implement to my code by extending/overriding some methods. But I'm stuck with chainability. For example:
class MomentPHP extends Moment {
public $uniqueSettings;
public function formatJS(){
return parent::format($this->uniqueSettings);
}
}
class Moment {
public function startOf(){
//some code
return $this;
}
}
I want to do this:
$momentphp = new MomentPHP();
$dateStart = $momentphp->startof('month')->formatJs();
And the way to do this is overriding all the methods in the child class inside MomentPHP to return itself.
Is there any other simple way to do this? like using _call or something?
Edit: Found one way to do this:
Remove the inheritance,
Create a instance variable of parent class,
use __call method to switch between classes.
Like this:
class MomentPHP {
private $instance = null;
public $uniqueSettings;
public function __construct(){
$this->instance = new Moment();
}
public function __call($method,$args){
if(in_array($method, get_class_methods($this))){
call_user_func(array($this,$method),$args);
else
call_user_func(array($this->instance,$method),$args);
return $this;
}
public function formatJS(){
return $this->instance->format($this->uniqueSettings);
}
}
class Moment {
public function startOf(){
//some code
return $this;
}
}
Is there any better way?
One proper way to do this is:
class MomentPHP {
private $instance = null;
public $uniqueSettings;
public function __construct(){
$this->instance = new Moment();
// settings etc.
}
public function __call($method,$args){
$result = NULL;
if(in_array($method, get_class_methods($this))){
$result = call_user_func(array($this,$method),$args);
else
$result = call_user_func(array($this->instance,$method),$args);
if($result instanceof Moment)
$this->instance = $result;
return $this;
}
public function format(){
return $this->instance->format($this->uniqueSettings);
}
}
Updating the instance from the method result is the key operation, and using $this instead of $this->instance allows you to use the extender class in every call. So you can override the function while using other methods in the parent class with chaining ability.

Call object that another object is contained in

So I'd like to be able to call a method of an object from a created object as deep as I'd like.
For example
$test = new sampleObject;
$test2 = $test->createChild();
$test3 = $test2->createChild();
...
catch is, I need to be able to refer to a method from the topmost creator class.
so I have my main class
class sampleObject
{
public $tons, $of, $properties;
public function createChild()
{
$someVar = new childObject();
$this->otherMethod();
return $someVar();
}
public function otherMethod()
{
//Do some stuff
}
}
class childObject
{
public $child, $properties;
function createChild()
{
$someVar = new childObject();
//here is my issue
//I need to call a otherMethod from the creating class here but not static .
return $someVar;
}
}
Is this the wrong approach or is there a way to reference that creating class object.
I'd like to keep the created object's properties secluded from the creator class.
I thought about just passing the object, but I'd like to keep the same structure if possible as the creator class.
The best way I could find to do this was to pass the object that it is a part of to the sub-object.
so $test2 = $test->createChild($test);
and
class childObject
{
public $child, $properties, $parent;
function createChild()
{
$someVar = new childObject($parent);
$this->parent = $parent;
//here is my issue
//I need to call a otherMethod from the creating class here but not static .
return $someVar;
}
}

How can I create a singleton in PHP?

I'm using PDT and Aptana on Eclipse Indigo with PHP 5.3 and I want to create a singleton in a class.
By singleton, I mean I want to just have one instance of that object, and for other objects or classes to get that single instance via a function that returns that object (so this would mean I'm trying to create an object within the class that defines that object, ie: creating objA within the class objA)
I understand you can't just go a head and do this:
public $object = new Object();
with in a class definition, you have to define it in the constructor.
How can I go ahead and do this? I'm coming from Java, so it could be I'm confusing some basic stuff. Any help is greatly appreciated. Here's the code:
<?php
class Fetcher{
private static $fetcher = new Fetcher(); //this is where I get the unexpected "new" error
static function getFetcherInstance(){
return $this->$fetcher;
}
}
?>
Solved! Thanks for all the help guys!
try this:
<?php
class myclass{
private static $_instance = null;
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new myclass();
}
return self::$_instance;
}
}
?>
and call it with:
<?php
$obj = myclass::getInstace();
?>
You cannot assign a class property in PHP like that. It must be a scalar, or array value, or the property must be set in a method call.
protected static $fetcher;
static function getFetcherInstance(){
if (!self::$fetcher) {
self::$fetcher = new Fetcher();
}
return self::$fetcher;
}
Also, notice that I did not use $this->, as that only works for object instances. To work with static values you need to use self:: when working within the class scope.
You might want to just read common design patterns on the php site. There are pretty good examples with good documentation:
http://www.php.net/manual/en/language.oop5.patterns.php
Else, a singleton is simply a method that returns one single instance of itself:
class MySingletonClass {
private static $mySingleton;
public function getInstance(){
if(MySingletonClass::$mySingleton == NULL){
MySingletonClass::$mySingleton = new MySingletonClass();
}
return MySingletonClass::$mySingleton;
}
}
Building on #periklis answer you might want separate singletons for different application scopes. For example, lets say you want a singleton of a database connection - fine. But what if you have TWO databases you need to connect too?
<?php
class Singleton
{
private static $instances = array();
public static function getInstance($name = 'default')
{
if ( ! isset(static::$instances[$name]))
{
static::$instances[$name] = new static();
}
return static::$instances[$name];
}
}
Class DB extends Singleton {}
$db_one = DB::getInstance('mysql');
$db_two = DB::getInstance('pgsql');
Alse define __clone method
class Fetcher {
protected static $instance;
private function __construct() {
/* something */
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Fetcher();
}
return self::$instance;
}
private function __clone() {
/* if we want real singleton :) */
trigger_error('Cannot clone', E_USER_ERROR);
}
}
Basically implementing a singleton pattern means writing a class with a private constructor and a static method to build itself. Also check PHP site for it: http://www.php.net/manual/en/language.oop5.php and http://it2.php.net/manual/en/book.spl.php
class A {
protected $check;
private function __construct($args) {
}
static public function getSingleton($args) {
static $instance=null;
if (is_null($instance)) {
$instance=new A();
}
return $instance;
}
public function whoami() {
printf("%s\n",spl_object_hash($this));
}
}
$c=A::getSingleton("testarg");
$d=A::getSingleton("testarg");
$c->whoami(); // same object hash
$d->whoami(); // same object hash
$b= new A("otherargs"); // run time error
<?php
class MyObject {
private static $singleInstance;
private function __construct() {
if(!isset(self::$singleInstance)) {
self::$singleInstance = new MyObject;
}
}
public static function getSingleInstance() {
return self::$singleInstance;
}
}
?>
class MyClass {
private static $instance;
public static function getInstance() {
if( !isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
}
Then call get instance using
MyClass::getInstance();

Object Oriented Programming Problem

I'm designing a little CMS using PHP whilst putting OOP into practice. I've hit a problem though.
I have a page class, whos constructor accepts a UID and a slug. This is then used to set the properties (unless the page don't exist in which case it would fail). Anyway, I wanted to implement a function to create a page, and I thought ... what's the best way to do this without overloading the constructor. What would the correct way, or more conventional method, of doing this be?
My code is below:
<?php
class Page {
private $dbc;
private $title;
private $description;
private $image;
private $tags;
private $owner;
private $timestamp;
private $views;
public function __construct($uid, $slug) {
}
public function getTitle() {
return $this->title;
}
public function getDescription() {
if($this->description != NULL) {
return $this->description;
} else {
return false;
}
}
public function getImage() {
if($this->image != NULL) {
return $this->image;
} else {
return false;
}
}
public function getTags() {
if($this->tags != NULL) {
return $this->tags;
} else {
return false;
}
}
public function getOwner() {
return $this->owner;
}
public function getTimestamp() {
return $this->timestamp;
}
public function getViews() {
return $this->views;
}
public function createPage() {
// Stuck?
}
}
PHP Doesn't support overloading. I would probably go for something like:
$oPage = new Page();
$oPage->setTitle($sSomeTitle);
$oPage->setcontent($sSomeContent);
$oPage->save();
Or you could create an extra object - that is responsible for handling this.
$oPage = new Page();
$oPage->setTitle($sSomeTitle);
$oPage->setcontent($sSomeContent);
PageManager::create($oPage);
The advantage of this - is that your page class remains a pure data container, where all logic for loading/saving is done within an separate class.
I put those arguments in a constructor without which an object cannot exist. Other (optional) attributes of an object can be set by calling its setters.
For example, in your case a page seems to always have a UID, without which your system cannot recognize it, so it should be an argument to the constructor and I would build it such that the callee of the constructor shall not be able to call an empty constructor, because it won't mean anything for the page class.
A page can have no content and not even any title, but it has no meaning for the system without a UID or for example a URI. So my callee's code would look as follows:
$page = new Page($uid);
$page->setTitle($sSomeTitle);
$page->setcontent($sSomeContent);
$page->render();
However, my discussion mainly pertains to modelling your class. I personally think that the second solution in Wesley's answer is better.
You can make static method, that returns Page object
public static function CreatePageWithExtraAttribute($uid, $slug, $extra) {
$page = new Page($uid,$slug);
//your code here
return $page;
}
Or make a static method that querys database for example
public static function CreatePage($extra) {
list($uid,$slug) = SomeDatabaseManager::GetUidSlug();
$page = new Page($uid,$slug);
//your code here
return $page;
}
Then use it
$page=Page::CreatePageWithExtraAttribute($title)

Categories