I have a RESTful API that I need to inteact with using CURL. I have created a wrapper class that has a static function with the CURL code.
class ApiInvoke
{
public static function execute($username, $password, $endpoint, $data = array(), $options = array())
{
//Rest of the CURL code goes here.....
}
}
I the created a class where I call the static APIInvokve class method to actually execute the API call. Below is the consumer class for ApiInvoke class above.
require "api_invoke.php"
class FlowgearConnect
{
//Properties go gere
public function getResults($model, $workflow, $data)
{
$endpoint = $this->getEndpoint($model, $workflow);
$results = array();
if(!is_null($endpoint)){
$results = ApiInvoke::execute('username', 'password', $endpoint, $data array('timeout' => 30));
}
return $results;
}
//....
}
Then I have a ParentClass class that create an instance of FlowgearConnect object which is made avalable to sub-classes. However, all subclasses are are processed inside the same parent class.
class ParentClass
{
private $Flowgear;
public function init()
{
$this->Flowgear = new FlowGearConnect(); //Assuming it has been required somewhere
}
}
Then we may have ChildClassA and ChildClassB which extends ParentClass. By vartue of the child classes extending the parent class they have access to the instance of $this->Flowgear object already because below is how the FlowgearConnect class is used:
class ChildClassA
{
public function getResults()
{
$results = $this->Flowgear->getResults('child_a', 'latestEvents', array());
}
}
ChildClassB has the very same function or rather exact except it might be responsible for getting a list of orders for example.
How these child classes are processed inside the parent class is depicted below:
//A function inside the ParentClass to process ChildClassA and ChildClassB
public function processModules()
{
$modules = $request->getModules();
foreach($modules as $module){
require_once "modules/' . $module;
$Module = new $module();
$Module ->getResults();
}
}
Something along these lines is not right.... Basically the extending class creates an instance of a class that is used by child classes. Somewhere somehow something is not right here and I guess it has everything to do with the facy that I am not using singgleton. I could if I new how to where CURL is concerned.
Stupid of me to ever thought I could never be able to create just one instance of a curl object thanks to Rayhan’s Http Client class (http://raynux.com/blog/2009/06/13/http-client-class-for-php-development/).
Basically what I wanted was to create a CURL SINGLETON class such that I do not have instances of the same object created over and over again.
Below is a skeleton of how I went about to achieve this:
class Flowgear
{
static private $_instance;
//Rest properties here...
public function __cosntsruct()
{ $this->_token = $this->_username .':'. $this->_passoword; }
public function execute()
{
//Call a class that handles the actual API invocation passing all relevant data
}
static public function &getInstance()
{
if(self::$_instance == null){
self::$_instance = new self;
}
return self::$_instance;
}
}
Then I simply get a single instance of the class by calling Flowgear::getInstance();
Related
I am building an MVC component and I'm getting stuck with an issue with a parent and child model. I have a few methods in the parent Model and they're not working with the database_class object
the constructor works fine
but when I use that object in the methods its like the constructor doesn't exist?
Class Controlller
{
public function __construct()
{
$this->childModel = $this->model('childModel');
} // end construct
// methods go here
}
Here are the models:
class childModel extends parentModel {
private $dbo;
public function __construct()
{
$dbobj = new Database_class;
$this->dbo = $dbobj;
}
//methods
}
class parentModel {
private $dbom;
public function __construct()
{
$dbombj = new Database_class;
$this->dbom = $dbombj;
var_dump($this->dbom); //working perfectly as database object
}
public function methodName()
{
var_dump($this->dbom); //not showing up as database object
}
}
I don't think this code is doing what you think it's doing. In childModel, you are overwriting the __construct method of the parentModel, so the __construct in the parentModel never gets called. Therefore $this->dbom should be null. Furthermore if you wish to use $this->dbom from the childModel, you should probably change the scope from private $dbom to protected $dbom. See this page for more info on that: http://php.net/manual/en/language.oop5.visibility.php
I have this class
class Base
{
// This class contains a lot of private method which are using inside this class
private function CreateRequest()
{
//using curl to send request
}
}
class API_CALLS extend Base
{
//Here i want to create a static class to make API calls to server, but i need to use create request method from base class
static public get_name()
{
$params = array();
$this->CreateRequest($params); // i know this causes the error
}
}
What is the best way to create a class structure in my case?
you must know the meaning of "private","static","$this" in class.
class Base
{
protected static function CreateRequest()
{
//using curl to send request
}
}
class API_CALLS extends Base
{
static function get_name()
{
$params = array();
self::CreateRequest($params);
}
}
I have a Factory Method to instance a class. Is there a way to prevent this class from direct instancing?
The only option I see is to use an argument passed into the __construct(), but that's not something I'm looking for.
On the other hand, making the __construct() private would be ideal, but I don't want MyClass to extend the Factory without actual need.
What do you guys think?
Factory Method:
class Factory
{
public static function instance()
{
return new MyClass(true);
}
}
MyClass:
class MyClass
{
public function __construct($isFactory = false)
{
if (!$isFactory) {
throw new Exception('Use Factory::instance() to create an object');
}
}
}
There are hacks to do that:
abusing inheritance to use a protected constructor
putting the factory method inside the class so that it can call the private constructor, which is actually not a hack. But then why not using the constructor in the first place?
using reflection to access the private constructor
I'm not promoting anything of that. What I personally do is documenting the API with things like #internal and leave it to the client following that contract.
In essence, your code should have read something like this:
THE FACTORY
<?php
class Factory {
public static function instance(){
return new MyClass(true); //HERE YOU ARE INSTANTIATING
}
}
THE CLASS TO BE INSTANTIATED VIA THE FACTORY
<?php
//NOT MyClass() <--- YOU ARE DEFINING.... NOT INSTANTIATING...
class MyClass {
public function __construct($isFactory = false) {
if (!$isFactory) {
throw new Exception('Use Factory::instance() to create an object');
}
}
//...MORE METHODS
}
Could you try this instead?
<?php
class Factory
{
private static $FACTORY_GUARANTOR; //ONLY SET DURING INSTANTIATION
public static function instance($type) {
if (class_exists($type)) {
self::$FACTORY_GUARANTOR = 1;
$instance = new $type();
self::$FACTORY_GUARANTOR = null;
return $instance;
}
else {
throw new Exception("Class not found...");
}
}
//YOU CAN GET $FACTORYGUARANTOR EXTERNALLY BUT NEVER SET IT;
public static function getGuarantor(){
return self::$FACTORY_GUARANTOR;
}
}
class MyClass {
protected $property1;
protected $property3;
protected $property2;
public function __construct() {
// IF SOMEONE TRIES TO INSTANTIATE THE CLASS OUTSIDE OF THE FACTORY... BLOW A WHISTLE
if(!Factory::getGuarantor()){
throw new Exception('Use Factory::instance() to create an object');
}
// IF THE PROGRAM MADE IT TO THIS POINT;
// JUST INSTANTIATE THE CLASS BECAUSE MOST LIKELY IT IS COMING FROM THE FACTORY
var_dump($this); // A LITTLE CONFIRMATION....
}
//...MORE METHODS
}
// TRY IT OUT:
/*INSTANCE A: RIGHT*/ $theClass = Factory::instance("MyClass"); //INSTANTIATES THE CLASS
/*INSTANCE B: WRONG*/ $theClass = new MyClass(); //THROWS AN EXCEPTION
The easiest way is to define your base class as abstract. The abstract classes cannot be directly instanced, so you will have to redefine their abstract members in the inherited classes:
abstract class Factory
{
abstract public function foo();
}
class InheritedClass extends Factory
{
public function foo()
{
// Do something
}
}
// $obj1 = new Factory(); // Will produce an error
$obj1 = new InheritedClass(); // Will be executed successfully
You can read more for the abstract classes here: PHP: Class Abstraction - Manual.
For me, the best way is to use ReflectionClass:
class MyClass
{
public const FRIEND_CLASSES = [Factory::class];
protected function __construct() {}
}
trait Constructor
{
protected function createObject(string $className, array $args = [])
{
if (!in_array(static::class, $className::FRIEND_CLASSES)) {
throw new \Exception("Call to private or protected {$className}::__construct() from invalid context");
}
$reflection = new ReflectionClass($className);
$constructor = $reflection->getConstructor();
$constructor->setAccessible(true);
$object = $reflection->newInstanceWithoutConstructor();
$constructor->invokeArgs($object, $args);
return $object;
}
}
class Factory
{
use Constructor;
public function MyClass(): MyClass
{
return $this->createObject(MyClass::class);
}
}
In constant FRIEND_CLASSES you can define in which classes the class can be instanced.
trait is used because this functionality can be used in different factories that are not related.
If you need to put parameters into constructor of the class, put them as second parameter of createObject.
Details I described in the article "Forbidding of creating objects outside factory in PHP"
I have a parent class that depends on whether child class are instantiated.
class GoogleApp {
protected $auth_token;
public function __construct($scopes) {
$this->auth_token = $scopes;
}
}
class Gmail extends GoogleApp {
public function __construct() {
print_r($this->auth_token);
}
}
$googleApp = new GoogleApp('gmail'); // Change the actual class for all child instances
$gmail = new Gmail();
The idea is that all the children use the same auth_token (which is generated on whether the child classes are used - as of now, I'm just manually adding them to whether I included them in my code). Since I have quite a few child classes (like Calendar or Drive), do I have to inject the parent into each child instance or is there an easier way?
If I understand your request correctly, you're pretty close, you just need to declare your property as static.
class FooParent
{
protected static $scope = null;
public function __construct($scope)
{
self::$scope = $scope;
}
public function getScope()
{
return self::$scope;
}
}
class FooChild extends FooParent
{
public function __construct()
{
if (self::$scope === null) {
throw new Exception('Must set scope first.');
}
}
}
$parent = new FooParent('foo');
$child = new FooChild();
echo $child->getScope(), "\n"; // prints "foo"
I am trying to call different methods within same controller written using Codeigniter through separate AJAX calls and create an object of a Third Library in one of those calls and later access the same object (also autoloaded SESSION library) in second method while making second AJAX Call:
Javascript has 2 separate AJAX Calls:
$.post('http://mysite.com/UserController/controllerA',{Param1:x,Param2:y});
$.post('http://mysite.com/UserController/controllerB');
And the controller looks like:
require_once 'FILEPATH/Thirdlibrary.php';
class UserController extends CI_Controller {
protected $service;
public controllerA{
$varA = $this->input->post('Param1');
$varB = $this->input->post('Param2');
$this->service = new ThirdLibray($varA,$varB);
$this->service->startCall();//Thirdlibrary has method startCall() and stopCall
}
public controllerB{
//I want to refer to the same object $this->service here
$this->service->stopCall();
}
Now I know that PHP re-initializes the objects each time its loaded/visited, how could I make this work.How to ovecome such error:
Call to a member function stopCall() on a non-object
(Querying here after making all the efforts searching and coding)
store the object into session and use it.
require_once 'FILEPATH/Thirdlibrary.php';
class UserController extends CI_Controller {
protected $service;
public controllerA{
$varA = $this->input->post('Param1');
$varB = $this->input->post('Param2');
if($this->session->userdata('lib_service'))
{
$this->service =$this->session->userdata('lib_service');
}
else
{
$this->service = new ThirdLibray($varA,$varB);
}
$this->service->startCall();//Thirdlibrary has method startCall() and stopCall
$this->session->set_userdata('lib_service',$this->service); // Why i am saving the object here?, startCall may update some object properties, so that-also will be saved. Otherwise you can have this line in the else part above, after object creation.
}
public controllerB{
//I want to refer to the same object $this->service here
if($this->session->userdata('lib_service'))
{
$this->service =$this->session->userdata('lib_service');
$this->service->stopCall();
// Here after stop if you don't want the object, you can clear from session.
}
}
You can try with Singleton pattern for php. This is the basic code for implement it for your situation but I'm not sure it will work for you. Let's try:
First create a wrraped class for your third party library: ThirdlibraryWrapped.php that you can see more about singleton Best practice on PHP singleton classes
class ThirdLibraryWrapped{
public ThirdLibray thirdLibrary;
public static function Instance($param1=null,$param2 = null)
{
static $inst = null;
if ($inst === null) {
$inst = new ThirdlibraryWrapped($param1,$param2);
}
return $inst;
}
private function __construct($param1,$param2)
{
if($param1!=null && $param2 != null)
thirdLibrary = new ThirdLibrary($param1,$param2);
else
//default constructor of thirdLibrary
thirdLibrary = new ThirdLibrary();
}}
For your controller code:
require_once 'FILEPATH/ThirdlibraryWrapped.php';
class UserController extends CI_Controller {
protected $service;
public controllerA{
$varA = $this->input->post('Param1');
$varB = $this->input->post('Param2');
$this->service = ThirdlibraryWrapped::Instance($varA,$varB);
$this->service->thirdLibrary->startCall();//Thirdlibrary has method startCall() and stopCall
}
public controllerB{
//I want to refer to the same object $this->service here
$this->service = ThirdlibraryWrapped::Instance();
$this->service->thirdLibrary->stopCall();
}}