PHP static method call with namespace in member variable - php

is it possible to do something like this in php? I want to have a namespace in a member variable and just always be able to call every static method of that class like I'm doing below.
Of course my code doesn't work, but I'm just wondering if that is possible at all and that I'm close to a solution, or if that's completely out of the question and must always use the syntax:
\Stripe\Stripe::setApiKey(..);
Similar question for clarifications
NOTE: I cannot modify the Stripe class, it's important it stays untouched for when future devs must update the Stripe API
Simplified code:
class StripeLib
{
var $stripe;
public function __construct()
{
// Put the namespace in a member variable
$this->stripe = '\\'.Stripe.'\\'.Stripe;
}
}
$s = new StripeLib();
// Call the static setApiKey method of the Stripe class in the Stripe namespace
$s->stripe::setApiKey(STRIPE_PRIVATE_KEY);

Yes something like this is possible. There is is static class method which can be called which returns the namespace path of the class.
<?php
namespace Stripe;
Class Stripe {
public static function setApiKey($key){
return $key;
}
}
class StripeLib
{
public $stripe;
public function __construct()
{
// Put the namespace in a member variable
$this->stripe = '\\'.Stripe::class;
}
}
$s = (new StripeLib())->stripe;
// Call the static setApiKey method of the Stripe class in the Stripe namespace
echo $s::setApiKey("testKey"); //Returns testkey

I just tested it, yes you can do that in php.
But I think you violate Dependency Injection principle here.
The right way to do that is:
class StripeLib
{
var $stripe;
// make sure Stripe implements SomeInterface
public function __construct(SomeInterface $stripe)
{
// Stripe/Stripe instance
$this->stripe = $stripe;
}
}

Related

Laravel Service Provider - Get a class instance from an intermediate method in a method chain

I was wondering if you could help me with the following question. First of all, I would like to tell you that if I am asking this question here, it is because I have already tried many options and none have worked for me. It turns out that I am developing a package with Laravel and I am using Laravel's dependency injection. But I am at a crossroads from which I have not found a way out. I'm trying to get the instance of a class in an intermediate method from a method chain, let me explain. Here is the code very similar to what I have:
PackageServiceProvider.php
<?php
class PackageServiceProvider extends ServiceProvider
{
public function register()
{
$this->configureBindings();
}
private function configureBindings()
{
$this->app->when(A_Class::class)->needs(B_Interface::class)->give(function () {
return new B_Class();
});
}
...
A_Class.php
<?php
class A_Class implements A_Interface
{
private $b_interface;
public function __construct(B_Interface $b_interface)
{
$this->b_interface = $b_interface;
}
public function create($arg1, $arg2)
{
return $this->b_interface->method_1()->call_another_method_from_another_class();
}
}
A_Interface.php
<?php
interface A_Interface extends Arrayable, Rendereable
{
public function create($arg1, $arg2);
...
}
<?php
class B_Class implements B_Interface
{
public function __construct()
{
// Here is the question...
// How could I get here the instance of the class A_Class?
}
public function method_1()
{
// should return another class instance
}
public function method_2()
{
// should return another class instance
}
}
B_Interface.php
<?php
interface B_Interface
{
public function method_1();
public function method_2();
...
}
If you look at class B_Class``, in the __constructmethod I'm trying to get the instance of classA_Class``` from where that class is being called. I have tried the following:
class B_Class implements B_Interface
{
public function __construct(A_Interface $a_interface)
{
// Here is the question...
// How could I get here the instance of the class A_Class?
}
But I get the following error:
Segmentation fault
I guess there must be some way I can achieve what I need. I would appreciate any help in advance.
Because you are referring to class A inside your class B constructor, and class B in your class A constructor, you have introduced a cyclic dependency.
This will resolve to the error you are experiencing, which is the segmentation fault, as outlined here:
https://laravel.io/forum/11-08-2016-circular-dependency-causes-segmentation-fault-error-when-running-php-artisan-optimize
So the answer is to remove the cyclic dependency if possible, as you can have methods from A calling B that calls A for infinity at runtime, and you will get the above error above again.
If your class A and B are relatively small, I would recommend combining them before using a cyclic dependency.
For interest and prosperity, if you want achieve a cyclic dependency, this is possible by registering your Class A with a singleton from inside A's constructor, and putting the reference to the incomplete object into Class B with your code above. I try with laravels singleton here, its untested, but hopefully you'll get the idea.
class A_Class implements A_Interface
{
public function __construct(B_Interface $b_interface)
{
//I dont think you can pass $this to a function when construction is incomplete, hence $that.
$that = $this;
App::singleton('A_Class', function($that){
return $that;
});
$this->b_interface = $b_interface;
}
}
class B_Class implements B_Interface
{
public function __construct(A_Interface $a_interface)
{
//unfinished object, but no more error.
$this->aClass = App::make('A_Class')
}
}

php constructor variable not getting accessed in the functions below

I have initialized a new instance of a library in the __construct(){} method of a PHP class and equated it to a variable,
but now I want to use this variable to access methods of the library inside another function but PHP is not allowing me do that.
class Demo
{
public function __construct()
{
parent::__construct(new PaymentModel);
$this->api = new Api(config("razorpay", "key_id"), config("razorpay", "key_secret"));
}
public function createOrder()
{
$order = $api->order->create();
echo '<pre>';
var_dump($order); die;
}
}
I looked at the __construct documentation and some other answers here on stack overflow but all they did was confuse me more than helping me out.
Please help me figure this out as I am a starter myself in tech.
To be able to use $this->api in your class, you will need to set it as an attribute.
so :
class Demo
{
private $api;
public function __construct()
{
parent::__construct(new PaymentModel);
$this->api = new Api(config("razorpay", "key_id"), config("razorpay", "key_secret"));
}
public function createOrder()
{
$order = $this->api->order->create();
echo '<pre>';
var_dump($order); die;
}
}
Also, as notified by other, you are to construct a parent class while your class 'Demo' does not extend any other class.
You have defined api as a class variable (property). Use $this->api to acces this class variable (property) in other methods of your class.
// This class probably inherits some base class
class Demo extends BaseDemo
{
public function __construct()
{
parent::__construct(new PaymentModel);
$this->api = new Api(config("razorpay", "key_id"), config("razorpay", "key_secret"));
}
public function createOrder()
{
$order = $this->api->order->create();
echo '<pre>';
var_dump($order); die;
}
}
Also check your class definition - if parent::__construct() is called, then your class probably inherits some base class. If this is not the case, remove parent::__construct() call.
To access object variables you need to use $this. In your case change the first line in createOrder() to $order = $this->api->order->create();
Also you appear to be trying to run the classes parents constructor in your constructor. But the class doesn't have a parent.
you are calling parent::__construct(new PaymentModel); on a class which doeasn't extend any base class.
declare variable $api in a class then only accessible to other function body

How to use one function variable to another function in abstract class

abstract class Dropboxapi {
protected $webAuth;
protected function abi() {
require __DIR__.'/app/Dropbox/autoload.php';
self::start();
self::dropbox_auth();
}
public function start() {
$webAuth = new Dropbox\WebAuth($appInfo,$appName,'path',$csrfTokenStore);
}
public function dropbox_auth() {
$authUrl = $webAuth->start();
}
}
Dropboxapi::abi();
Here i have $webAuth object in start function. When I use this in dropbox_auth it shows Undefined variable: webAuth.
When i use $this->webAuth i'm getting Using $this when not in object context
i tried like self::webAuth also. This is showing Access to undeclared static property:. So I don't understand how to use that.
if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private.
Many example are there for abstract class.Just check how you can or not.As you asked without abstract just define the class and function like below.Here all the variable and methods are $this context.
class Dropboxapi {
public $this->webAuth='';
public function abi() {
require __DIR__.'/app/Dropbox/autoload.php';
$this->webAuth = new
Dropbox\WebAuth($appInfo,$appName,'path',$csrfTokenStore);
}
public function dropbox_auth() {
$authUrl = $this->webAuth->start();
}
}
$dropbox = new Dropboxapi();
$dropbox->dropbox_auth();
You are defining things wrong. Abstract class, similar with interface, are tend to be used as "blueprint" class. It means they need to be extended by another classes to be used, and cannot be used by itself as is. Using $this in abstract class is fine, as in documentation of abstract by php.net: http://php.net/manual/en/language.oop5.abstract.php.
What you need to do, is to have another class that inherit / extends that DropBoxApi class of yours, ex:
class DropBoxApi2 extends DropBoxApi
{
}
As class DropBoxApi2 is inherited, then it already has functions and property of it's parent (DropBoxApi). And you can use it like (example):
$api = new DropBoxApi2();
$api->start();
Additionally, the double colon that you use is static operator. Which is far far different concept than abstract.
Sample Code. Replace with your requirement.
you have to make everything as static
abstract class Dropboxapi {
protected static $webAuth;
public static function abi() {
self::start();
self::dropbox_auth();
}
public static function start() {
self::$webAuth = new Stdclass();
}
public static function dropbox_auth() {
var_dump(self::$webAuth);
}
}
Dropboxapi::abi();

Adding Parameters after creating an object OOP PHP

REVISED
I have a simple question, but being new to OOP I am not sure if this is possible.
Currently I have a class with one function that accepts an argument.
What the actual function does is irrelevant.
<?php
class Method {
public function show($parameter){
echo $parameter;
}
}
?>
I create the object like this...
$this->Method = new Method();
And use it like this...
$this->Method->show($parameter);
So the question is, can my function be set up in a way to simplify the use to
this...
$this->Method($parameter);
I tried by changing the function to a __construct and using the above line of code but it fails since the new Method() was created without a $parameter specified.
I was hoping to be able to pass the $parameter after the new Method(); was called.
Yes, you can do this. If you add an __invoke() method to your class, instances of that class can be called like you would a method.
class Method {
public function __invoke($param) {
echo $param;
}
}
Then you can use it in your class the way you want to
$this->Method = new Method;
$this->Method('something'); // echos something
If you still want to have the show method (or whatever the method actually is) as well, you can leave it there and just call it in __invoke instead.
class Method {
public function show($param) {
echo $param;
}
public function __invoke($param) {
$this->show($param);
}
}
Another possibility, because it looks like you are wanting to be able to use an object like you would use a function, is to define a trait and use it in the object that currently has a Method instead of using a Method class. If you create a trait like:
trait CanUseMethod {
public function Method ($parameter) {
echo $parameter;
}
}
Then in the class that needs to use Method, instead of
$this->Method = new Method;
You can use the trait like this:
class Example {
use CanUseMethod;
}
Then your Example class will be able to use Method without creating a new object.

Can't extend my Controller

I am trying to write an extension to my Controller class. The problem is I can't seem to figure out how..
I have the following class named test in which there is one function which simply returns aaaa and in in the same file, at the end, as my Controller:
class test extends Controller
{
function test()
{
parent::Controller();
}
function echoMe(){
return 'aaaaaaaaaaaaaaaaa';
}
}
Within my Controller class I have a function which is the general output for a clients homepage. I'm trying to call the function echoMe from the extension above, but I keep getting
Call to undefined method Controller::echoMe()
Here is the client function (the call to echoMe() is right at the top):
function controller_client1($controlData = NULL)
{
echo $this -> echoMe();
//as the client page is content from the xml, mmodel needs the page number
$pageNumber = '';
if(isset($_GET['number']))
{
$num = htmlentities($_GET['number']);
if(ctype_digit($num) && $num >= 0)
{
$pageNumber = $num;
}
}
else{
$pageNumber = 0;
}
//loading the page content
$data = $this->model->model_loadXMLdata($pageNumber);
if(!empty($controlData))
{
//check if there is any info in the control data sent
foreach($controlData as $key => $value)
{
//add the info to the data array
$data[$key] = $value;
}
}
$this->load->load_clientHomePage($data);
}
I know this is a very simple question. I've been trying to follow this guide, but something isn't clicking...
Could somebody please help? How can I call the function echoMe() from test?
I know how to write just a brand new class and call it, but I'm trying to learn how to extend properly and keep failing.
Am I meant to call the "test" from within the Controller somewhere?
In the config.php you set the prefix for the file you want to extend. So it should be My_test, unless you have changed this preset(displayed below)
/*
|--------------------------------------------------------------------------
| Class Extension Prefix
|--------------------------------------------------------------------------
|
| This item allows you to set the filename/classname prefix when extending
| native libraries. For more information please see the user guide:
|
| http://codeigniter.com/user_guide/general/core_classes.html
| http://codeigniter.com/user_guide/general/creating_libraries.html
|
*/
$config['subclass_prefix'] = 'MY_';
Make sure you have the controller in the right folder (application/core in codeigniter 2.1.0) then you shouldn't have a problem. Hope that helps
here is my controller that i extend. The file is called My_Controller.php (creative I know)
<?php
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
//constructor code here
}
//Custom functions here
}
//sencond controller I extend in the same file
class MY_Admin extends CI_Controller {
function __construct()
{
//more custom stuff for admin stuff
}
//more custom functions for admin stuff
}
?>
Has you see I have two extended controllers in the same file.
My extending code looks like this:
<?php
class home extends MY_Controller
{
and then just replace My_Controller with My_Admin if I want to extend the admin.
echoMe() function is defined in test class and not in Controller class. When controller_client1 function is called with the instance of Controller class, echoMe does not exist because it is not defined within Controller class.
The best way to achieve this is to create empty echoMe function in base Controller class. This way polymorphism works. When calling controller_client1 function from instance of test class, method from that class will be executed. Otherwise, method from base class will be executed.
I hope I didn't miss the point of the question :)
echo $this -> echoMe(); will fail because its created in the child(extended) class and your calling it in the parent class. The question is a little hard to understand.
abstract class Controller{
public function __construct(){
}
public function echoMe($str){
echo $str;
}
}
class test extends Controller{
public function __construct(){
parent::echoMe('aaaaaaaaaa');
}
}
Try this (general idea, not CodeIgniter only):
$test = new test();
echo $test->echoMe();
Remember, test extends your Controller class, not the other way round - so you can't call your methods outside the test class/object instance.
Also, it might be a good idea to upgrade to a new version of CodeIgniter - beware of the new parent controller name, though.
EDIT
Ok, this should be enought to get you started - note that it's PHP5, not PHP4, so constructors are called __construct and not the class name:
class Controller {
public $mainvar;
function __construct() {
$this->mainvar = '<br />';
}
function echoMe() {
return 'aaaaaaaaaaaaaaaaa';
}
}
class Test extends Controller {
function __construct() {
parent::__construct();
}
function echoMeAgain(){
return 'bbb';
}
}
$test = new Test();
echo $test->echoMe();
echo $test->mainvar;
echo $test->echoMeAgain();
I think the question has actually already been answered by Kosta, but there might be some misunderstanding at your side. So let me extend that by some example code:
class Controller {
public function run() {
$this->echoMe();
}
}
class test extends Controller {
public function echoMe() {
echo "works";
}
}
// This does NOT work, because Controller::echoMe does not exist
$controller = new Controller();
$controller->run();
// This DOES work, because $this will be instance of test, and
// test::echoMe exists and is callable.
$test = new Test();
$test->run();
"extends" does not mean, that the actual Controller class gets extended. The new class "test" just inherits every single method and property that is not declared "private" from the Controller class. The Controller class itself remains untouched.

Categories