Say I have a function from an Object :
class Cat {
protected $sound = 'MeOwWw~';
public function make_a_big_and_nice_sound () { echo $this->sound; }
}
$C = new Cat;
$C->make_a_big_and_nice_sound ();
Now, the function's name could be long and the content depends on some properties of the object itself so It can't be rewrite outside of the Object.
But let's say I kind of have only one cat to birth and I want to make it meow a lot of time in my code here and there. What I want to do is the following :
main.php
function please_meow = $C->make_a_big_and_nice_sound;
please_meow ();
If your method names are long there is a big chance your method is simple doing too much. A method should only do one single thing.
So you should really actually fix your code instead.
Considering you don't provide your actual code (which would have helped pointing out the actual flaw in your code) and if you really insist on doing this (you really shouldn't) you could use a closure for this:
$please_meow = function() use ($C) {
return $C->make_a_big_and_nice_sound();
};
$please_meow();
But again if you need this you are doing it wrong.
If you use PHP 5.3 or above, try this:
$please_meow = function() use($C) { $C->make_a_big_and_nice_sound(); };
$please_meow();
Now, the function's name could be long and the content depends on some properties of the object itself so It can't be rewrite outside of the Object.
But let's say I kind of have only one cat to birth and I want to make
it meow a lot of time in my code here and there
You can do something like this
class Cat
{
protected static $instance;
function __construct()
{
self::$instance = $this;
}
public static function please_meow()
{
self::$instance->make_a_big_and_nice_sound();
}
protected $sound = 'MeOwWw~';
public function make_a_big_and_nice_sound () { echo $this->sound; }
}
new Cat();
Cat::please_meow();
Cat::please_meow();
// some other codes
Cat::please_meow();
Related
I have a class that generates data based on a few things. I would like to format that data from the outside. So I am trying to pass a function into the class so that it would format that data. I have looked at many examples, but it seems this is unique.
Can anybody give an idea of how to do this? The following code gives an error.
<?php
class someClass {
var $outsideFunc; // placeholder for function to be defined from outside
var $somevar='Me'; // generated text
function echoarg($abc){
$outsideFunc=$this->outsideFunc; // bring the outside function in
call_user_func($outsideFunc,$abc); // execute outside function on text
echo $abc;
}
}
function outsidefunc($param){ // define custom function
$param='I am '.$param;
}
$someClass=new someClass();
$someClass -> outsideFunc = 'outsideFunc'; // send custom function into Class
$someClass -> echoarg($someClass->somevar);
$someClass -> outsidefunc = 'outsidefunc';
In PHP, function names are not case sensitive, yet object property names are. You need $someClass->outsideFunc, not $someClass->outsidefunc.
Note that good OOP design practice calls for the use of getter and setter methods rather than just accessing properties directly from outside code. Also note that PHP 5.3 introduced support for anonymous functions.
Yeah. You are right. Now there is no error. But it does not work either.
By default, PHP does not pass arguments by reference; outsidefunc() does not actually do anything useful. If you want it to set $param in the caller to something else, and do not want to just return the new value, you could change the function signature to look like this:
function outsidefunc(&$param) {
You would also need to change the way you call the function, as call_user_func() does not allow you to pass arguments by reference. Either of these ways should work:
$outsideFunc($abc);
call_user_func_array($outsideFunc, array(&$abc));
Why not pass your function as an argument?
<?php
class someClass {
public $somevar="Me";
public function echoarg($abc,$cb=null) {
if( $cb) $cb($abc);
echo $abc;
}
}
$someClass = new someClass();
$someClass->echoarg($someClass->somevar,function(&$a) {$a = "I am ".$a;});
i am not sure what exactly you are looking for, but what i get is, you want to pass object in a function which can be acheive by
Type Hinting in PHP.
class MyClass {
public $var = 'Hello World';
}
function myFunction(MyClass $foo) {
echo $foo->var;
}
$myclass = new MyClass;
myFunction($myclass);
OP, perhaps closures are what you're looking for?
It doesn't do EXACTLY what you're looking for (actually add function to class), but can be added to a class variable and executed like any normal anonymous function.
$myClass->addFunc(function($arg) { return 'test: ' . $arg });
$myClass->execFunc(0);
class myClass {
protected $funcs;
public function addFunc(closure $func) {
$this->funcs[] = $func;
}
public function execFunc($index) { $this->funcs[$index](); } // obviously, do some checking here first.
}
ok I do have the code below
<?php
class foo{
public $bar = NULL;
public function boo(){
$this->bar();
}
}
$mee = new foo();
//save a closure function on the property
$mee->bar = function(){
echo 'hahaha';
};
//invoke the closure function by using a class method
$mee->boo();
?>
and you can see it running here http://codepad.org/s1jhi7cv
now what i want here is to store the closure function on the class method.
well closures are possible as i read the documentation about it here http://php.net/manual/en/functions.anonymous.php
is this possible? did i went to something wrong? please correct me
Your example code at codepad.org does not work because codepad.org uses PHP 5.2.5, and closure support was only added in 5.3.
However, your code will also not work in a PHP version that supports closures, although you will get a different error: http://codepad.viper-7.com/Ob0bH5
This is a limitation of PHP at present. $obj->member() looks for a method named member and will not look at properties to see if they are callable. It is, frankly, annoying.
The only way I am aware of to make this work without call_user_func()/call_user_func_array() is:
public function boo() {
$func = $this->bar;
$func();
}
You need to exploit some magic functionality of PHP (__call) to make use of that. Extend from Extendable for example:
class Extendable {
static function import($context) {
$self = new static();
while (is_callable($context)) $context = $context($self);
if (is_array($context) || is_object($context) || is_a($context, 'Traversable')) {
foreach($context as $key => $value)
$self->$key = &$value; # preserve keys if
}
return $self;
}
public function __call($name, $args) {
if (isset($this->$name) && is_callable($this->$name)) {
return call_user_func_array($this->$name, $args);
}
throw new BadFunctionCallException(sprintf('Undefined function %s.', $name));
}
}
And you can do the job. It's not that nice. Background and examples are in one of my blog posts:
PHP: Extending stdClass with Closures (plus Visitor)
You can naturally implement that magic functionality your own, too.
Use call_user_func() function:
<?php
class foo{
public $bar = NULL;
public function boo(){
call_user_func($this->bar);
}
}
$mee = new foo();
//save a closure function on the property
$mee->bar = function(){
echo 'hahaha';
};
//invoke the closure function by using a class method
$mee->boo();
This will display "ahahah"
Hope it helps.
You will not be able to do that.
Take for example this code:
class T {
function foo() {
echo 'T::foo';
}
}
$t = new T;
$t->foo = function() {
echo 'Closure::foo';
};
$t->foo();
It works fine on PHP 5.4.6 and/or PHP 5.3.16, however it will result in T::foo getting printed.
This happens because methods, in PHP, are not modifiable class properties, as they are for example in javascript.
However,
$foo = $t->foo;
$foo();
will print Closure::foo as expected.
PHP is not a prototype based language hence you cannot redefine functions
Use __call to catch all non-defined methods and then look up the closure and invoke it. Take a look at my post on this SitePoint thread.
Starting at php 7, you can put round brackets around the instance and method to call the method like so: ($this->bar)();.
This appears to cause a syntax error on earlier versions however.
I'm working on a project which requires a function to be copied & executed on the fly and variables in it needs to be replaced on the fly too.
A simple example will be like this:
function myfunction()
{
$abc = $_SESSION['abc'];
return $abc;
}
I want to be able to call myfunction1() which does NOT physically exist in the code but does exactly the samething as the one above except it now take values from my custom variable so it'll look like this:
function myfunction1()
{
$abc = $myCustomVariable;
return $abc;
}
Any one help pls?
The more you describe how convoluted your function is, the more it sounds like a perfect candidate for an object with injected dependencies.
For instance, you could have (just going to describe the basic interfaces here):
class myClass
{
public function __construct($provider DataProvider)
{
$this->provider = $provider;
}
// Please name this something better
public function doStufferer()
{
if ($this->provider->hasParam('foo'))
{
return $this->provider->getParam('foo');
}
}
}
class SessionProvider implements DataProvider
{
// Session specific stuff
}
class OtherProvider implements DataProvider
{
// Other provider stuff
}
interface DataProvider
{
public function getParam($key);
public function hasParam($key);
public function setParam($key, $value);
}
You can then use it like this:
$dataProcessor = new myClass(new SessionProvider);
// OR $dataProcessor = new myClass(new OtherProvider);
$dataProcessor->doStufferer();
Please take a look at PHP Classes and Objects and the other related topics.
This is what parameters are for, I think your looking todo something like this:
$myCustomVariable = 'Some value';
function myfunction($var=$_SESSION['abc'])
{
$abc = $var;
return $abc;
}
myfunction(); //returns $_SESSION['abc']
myfunction($myCustomVariable); //returns "Some Value"
The direct answer is eval which I do not recommend.
You could have your function accept a parameter, like this.
function myfunction1($some_var)
{
$abc = $some_var;
return $abc;
}
// call it like...
myfunction1($myCustomVariable);
If you need to access a variable, but the name is generated by dynamic code, you can use $GLOBALS.
function myfunction1($name_of_var)
{
$abc = $GLOBALS[$name_of_var];
return $abc;
}
// call it like...
$myCustomVariable = 'a value'
myfunction1('myCustom' + 'Variable');
I know you can assign a function's return value to a variable and use it, like this:
function standardModel()
{
return "Higgs Boson";
}
$nextBigThing = standardModel();
echo $nextBigThing;
So someone please tell me why the following doesn't work? Or is it just not implemented yet? Am I missing something?
class standardModel
{
private function nextBigThing()
{
return "Higgs Boson";
}
public $nextBigThing = $this->nextBigThing();
}
$standardModel = new standardModel;
echo $standardModel->nextBigThing; // get var, not the function directly
I know I could do this:
class standardModel
{
// Public instead of private
public function nextBigThing()
{
return "Higgs Boson";
}
}
$standardModel = new standardModel;
echo $standardModel->nextBigThing(); // Call to the function itself
But in my project's case, all of the information stored in the class are predefined public vars, except one of them, which needs to compute the value at runtime.
I want it consistent so I nor any other developer using this project has to remember that one value has to be function call rather then a var call.
But don't worry about my project, I'm mainly just wondering why the inconsistency within PHP's interpreter?
Obviously, the examples are made up to simplify things. Please don't question "why" I need to put said function in the class. I don't need a lesson on proper OOP and this is just a proof of concept. Thanks!
public $nextBigThing = $this->nextBigThing();
You can only initialize class members with constant values. I.e. you can't use functions or any sort of expression at this point. Furthermore, the class isn't even fully loaded at this point, so even if it was allowed you probably couldn't call its own functions on itself while it's still being constructed.
Do this:
class standardModel {
public $nextBigThing = null;
public function __construct() {
$this->nextBigThing = $this->nextBigThing();
}
private function nextBigThing() {
return "Higgs Boson";
}
}
You can't assign default values to properties like that unless that value is of a constant data type (such as string, int...etc). Anything that essentially processes code (such as a function, even $_SESSION values) can't be assigned as a default value to a property. What you can do though is assign the property whatever value you want inside of a constructor.
class test {
private $test_priv_prop;
public function __construct(){
$this->test_priv_prop = $this->test_method();
}
public function test_method(){
return "some value";
}
}
class standardModel
{
// Public instead of private
public function nextBigThing()
{
return "Higgs Boson";
}
}
$standardModel = new standardModel(); // corection
echo $standardModel->nextBigThing();
I'm not sure if this is a trivial questions but in a PHP class:
MyClass:
class MyClass {
public $var1;
public $var2;
constructor() { ... }
public method1 () {
// Dynamically create an instance variable
$this->var3 = "test"; // Public....?
}
}
Main:
$test = new MyClass();
$test->method1();
echo $test->var3; // Would return "test"
Does this work?? How would I get this to work? Ps. I wrote this quickly so please disregard any errors I made with setting up the class or calling methods!
EDIT
What about making these instance variables that I create private??
EDIT 2
Thanks all for responding - Everyone is right - I should have just tested it out myself, but I had an exam the next morning and had this thought while studying that I wanted to check to see if it worked. People keep suggesting that its bad OOP - maybe but it does allow for some elegant code. Let me explain it a bit and see if you still think so. Here's what I came up with:
//PHP User Model:
class User {
constructor() { ... }
public static find($uid) {
$db->connect(); // Connect to the database
$sql = "SELECT STATEMENT ...WHERE id=$uid LIMIT 1;";
$result = $db->query($sql); // Returns an associative array
$user = new User();
foreach ($result as $key=>$value)
$user->$$key = $value; //Creates a public variable of the key and sets it to value
$db->disconnect();
}
}
//PHP Controller:
function findUser($id) {
$User = User::find($id);
echo $User->name;
echo $User->phone;
//etc...
}
I could have just put it in an associative array but I can never correctly name that array something meaningful (ie. $user->data['name'] ... ugly.) Either way you have to know what is in the database so I do not really understand what the argument is that its confusing, especially since you can just var dump objects for debugging.
Why dont you just write the code and see for yourself?
<?php
class Foo
{
public function __construct()
{
$this->bar = 'baz';
}
}
$foo = new Foo;
echo $foo->bar; // outputs 'baz'
and
var_dump($foo);
gives
object(Foo)#1 (1) {
["bar"] => string(3) "baz"
}
but
$r = new ReflectionObject($foo);
$p = $r->getProperty('bar');
var_dump($p->isPublic());
will throw an Exception about 'bar' being unknown, while
$r = new ReflectionObject($foo);
$p = $r->getProperties();
var_dump($p[0]->isPublic());
will return true.
Now, should you do this type of assignment? Answer is no. This is not good OOP design. Remember, OOP is about encapsulation. So, if bar is describing some public property of the class, make it explicit and declare it in your class as public $bar. If it is supposed to be private declare it as private $bar. Better yet, dont use public properties at all and make them protected and provide access to them only through getters and setters. That will make the interface much more clearer and cleaner as it conveys what interaction is supposed to be possible with an object instance.
Assigning properties on the fly here and there across your code, will make maintaining your code a nightmare. Just imagine somewhere along the lifecylce of Foo someone does this:
$foo = new Foo;
$foo->monkey = 'ugh';
echo $foo->monkey; // outputs 'ugh'
Now, from looking at the class definition above, there is absolutely no way, a developer can see there is now a monkey patched into Foo. This will make debugging a pain, especially if code like this is frequent and distributed across multiple files.
Yes that will indeed work. Auto-created instance variables are given public visibility.
yes that works as you'd hope/expect.
I you wanted to make private variables on the fly you could use php magic functions to emulate this, e.g
MyClass
<?php
class MyClass {
public $var1;
public $var2;
private $data = array();
public function __get($key) {
// for clarity you could throw an exception if isset($this->data[$key])
// returns false as it is entirely possible for null to be a valid return value
return isset($this->data[$key]) ? return $this->data[$key] : null;
}
public function __set($key, $value) {
$this->data[$key] = $value;
}
}
?>
Main
<?php
$test = new MyClass();
$test->myVar = 'myVar is technically private, i suppose';
echo $this->myVar; // 'myVar is technically private
?>
Although these dynamically created variables are technically private, they are infact publicly accessible... i cannot image the purpose for wanting to dynamically create private instance variables. I would question your design.
Did you try it?
It is possible but you might get strict errors. If you dynamically need to create these variables, you are probably doing something wrong.
You should either change this into a function:
function var($no) { .. }
or use __get (http://ca.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members)