Adding Parameters after creating an object OOP PHP - 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.

Related

PHP static method call with namespace in member variable

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;
}
}

How to assign an object instance to a Behavior?

I'm struggling to get my Behavior class to use an object instance in the callbacks.
class SomethingBehavior extends ModelBehavior
{
public function setObject($obj)
{
// do stuff
}
public function afterFind(Model $model,$results,$primary)
{
// use the $obj reference set above
}
}
Now I need the Model class to call setObject(..) before any find operations are performed. So ideally I would just assign the object I need in the constructor.
class Document extends AppModel
{
//.....
public function __construct($id,$table,$ids)
{
parent::__construct($id,$table,$ds);
$this->Something->setObject(new MyClass());
}
}
My problem is that the Behavior object isn't yet configured, and I get a not an object error when trying to use it.
I can't find any callback method for Models like in Components. For example, there is no setup or initialize method.
How can I assign the object I need to the Behavior?
You don't seem to have worked with behaviors much. Try to use the containable, tree or other core or plugin behaviors, then you will soon figure out the basics.
First of all, behaviors are attached to models (and since 2.3: loaded), not the other way around. A model then gets "richer" in functionality.
Either statically be using public $actsAs or dynamically using
$this->Behaviors->attach('Something'); // since 2.3: load() instead of attach()
It can directly access the behavior methods. Lets say we have a method foo() in your behavior.
You can then call it from your model as
$this->foo($foo, $bar);
Or from your controller as
$this->Document->Behaviors->attach('Something')
$this->Document->foo($foo, $bar);
Awesome, right?
The behavior method usually has this declaration:
public function foo(Model $Model, $foo, $bar) {
$alias = $Model->alias;
// do sth
}
As you can see, you always pass the model into it implicitly (as first argument automatically passed).
You can access all its attributes.
And do not touch the constructor of the model. no need to do that.
If you really need to pass an object in at runtime, why does your approach not work?
public function setObject(MyClass $obj) {
$this->Obj = $obj;
}
Now you can internally use the object from your behavior methods
public function doSth(Model $Model) {
$this->Obj->xyz();
}
Also this might not be the most elegant approach.
You never set the something member of the Document class. You either need to instantiate it inside the constructor, or pass it in.
Personally, I would do something like this:
class Document extends AppModel
{
private $behavior;
public function __construct($id,$table,$ids, ModelBehavior $behavior)
{
parent::__construct($id,$table,$ds);
$this->behavior = $behavior
$this->behavior->setObject(new MyClass());
}
}
$doc = new Document(..., new SomethingBehavior());
Or better yet, you could even separate it further by doing:
class Document extends AppModel
{
private $behavior;
public function __construct($id,$table,$ids, ModelBehavior $behavior)
{
parent::__construct($id,$table,$ds);
$this->behavior = $behavior
}
}
$behavior = new SomethingBehavior();
$behavior->setObject(new MyClass());
$doc = new Document(..., $behavior);
That way, there is less magic going on in the constructor.

PHP dynamic methods in constructor

I want to be able to create methods within __construct
I tried using lambda in the following way
// This is what I am trying to achieve as an end result
class A extends Z{
public function __construct() {
parent::__construct()
}
public function myfunc() { // do something }
}
// This was an attempt to implement it
class A extends Z{
public function __construct() {
//example
if ($something_is_true) {
$this->myfunc = function () {}
}
parent::__construct()
}
}
I hope this explains what I am trying to achieve
EDIT
I have URLs mapped to functions, and I want to have some logic to determine what URL-mapped-functions exist on the class
Don't think that's possible. But another way to dynamically 'create' methods within a class is to use the magic __call() method.
With this method implemented, any attempt to call a non-existent method on an object will call the __call() method instead. The first parameter passed in will be the name of the function that the user called, and the second parameter will be the arguments.
See the manual for further details.
Once a class has been defined, you can't add new methods to it using standard PHP. I'd advise using __call as well but you can also accomplish what you want, if you're ok with using variable variables, by creating the function contents dynamically with create_function:
<?php
class A
{
public function __construct()
{
$this->addUpEchoAndReturn=create_function('$a,$b','$c=$a+$b;echo "$a+$b=$c<hr />";return $c;');
}
public function add_up_and_echo($a,$b,$c,$d)
{
$fn=$this->addUpEchoAndReturn;
return $fn($fn($a, $b),$fn($c, $d));
}
}
$x=new A();
$result=$x->add_up_and_echo(3,4,5,25);
echo "<hr /><hr />Final Result: $result";
?>

Is class being called from another class

Suppose I have the following code:
class siteMS
{
...
function __CONSTRUCT()
{
require 'config.php';
$this->config = new siteMSConfig;
...
}
...
}
From inside the siteMSConfig class can I determine weather or not it is being called from inside the siteMS class?
Yes, but there's no "pretty" way to do it - you'll end up looking through a backtrace or something similar.
It would be better to pass an (optional?) parameter to the siteMSConfig constructor like this:
class siteMSConfig
{
public function __construct($inSiteMS = false)
{
}
}
or alternatively, subclass siteMSConfig:
class siteMSsiteMSConfig extends siteMSConfig
{
public function __construct()
{
// Possibly call parent::__construct();
}
}
Technically yes, you could use debug_backtrace to figure out who your caller was.
Writing a class which alters its behaviour based purely on where it called from is asking for a world of pain later on though. Why not parameterise the different behaviour, or make a subclass?
I guess you have to pass it with variable, from what place you called it
$this->config = new siteMSConfig ('siteMS');

Initiate a class by calling a function that returns an instance of that class - PHP?

class foo(){
function bar()
{
$classInstance = $this->createClassInstance($params);
$result = $classInstance->getSomething();
}
function createClassInstance($params)
{
require 'path/to/class.php';
$myClass = new Class;
$myClass->acceptParams($params['1']);
$myClass->acceptMoreParams($params['2']);
.... lots more params
return $myClass;
}
}
Can I initiate a new class by calling a method that returns a class object? The class in question has lots of parameters and I need to call it multiple times within bar() so I thought it would be neater to do it that way, but I can't get it working and want to check if it's possible + good practice?
That's called factory class (Factory OO Design Pattern).
How it should be done in PHP: http://www.php.net/manual/en/language.oop5.patterns.php
What I think you're describing is the Factory pattern, but you're using parameters to set the class variables just like you would in a constructor, so why not just use that?
Edit:
Ah, if you're using the same parameters for the most part then you definitely want the Factory pattern. Just use a static function to return an instance of the class, and put it inside the type of class you're returning:
class MyClass
{
public static function factory($params)
{
$myClass = new MyClass;
$myClass->acceptParams($params['1']);
$myClass->acceptMoreParams($params['2']);
//.... lots more params
return $myClass;
}
}
class foo(){
function bar()
{
$classInstance = MyClass::factory(param1, param2);
}
}

Categories