Can you place an objected oriented code into a variable? - php

I wanted to make a piece of code reusable and wanted to do it with objected oriented code.
Is there a way to 'plugin' an object oriented code in any way? (look at my example below to see what I mean)
class Insert {
function insert_test($a, $b) {
return $a.$b;
}
}
$Insert = new Insert();
$insertplugin = "$Insert->insert_test('abc', '123')"; // the plugin of object oriented code
include_once("reusablecode.php");
reusablecode.php:
$something =1;
if($something >0)
{
$insertplugin;
}

Technically yes you can, you could call eval($insertPlugin); to run the code stored in a string. You would need to use single quotes to prevent the $Insert variable being converted into a string when you set the $insertPlugin variable.
However This is generally considered evil (particularly if your code is constructed from user input) See here: When is eval evil in php?
It depends on what you actually want to vary in your "plugin" as to what the correct approach would be. One approach would be to create a class that encapsulates the functionality you want.
class Command{
private $inserter;
public function __constructor($inserter){
$this->inserter=$inserter;
}
public function run(){
$this->inserter->insert_test('abc', '123');
}
}
$command = new Command(new Insert());
$something =1;
if($something >0)
{
$command->run();
}
Another would be to use lambda functions:
$insertPlugin=function() use ($Insert) {
$Insert->insert_test('abc', '123');
};
$something =1;
if($something >0)
{
$insertPlugin();
}
It sounds like you should probably do some more reading on OOP - I think what you basically want is a 'Command' class http://www.fluffycat.com/PHP-Design-Patterns/Command/ see in particular the use of an abstract class to allow you to define multiple different commands (or "plugins" as you called it)

Related

Use contents of string variable to call function

I have the following piece of code
copy($source, $target);
I also use
move_uploaded_file($source, $target);
To prevent code reuse, I want to pass copy and move_uploaded_file in via a variable.
If my variable is $var = "copy";, simply putting $var($source, $target);, doesn't seem to work.
Are there any special characters that must surround $var?
Thanks.
The correct syntax is $var (variable functions), so your code should work.
But please don't do that, just write the code in a straightforward and readable manner. There are legitimate use cases for this technique, but this is not one of them.
You want to look at Variable Functions which goes on to explain how to do that.
function foo() {
echo "In foo()<br />\n";
}
$bar = 'foo';
$bar(); //this calls foo()
This can also be done on both object methods and static methods.
Object Methods
class Foo
{
function MyFunction()
{
//code here
}
}
$foo = new Foo();
$funcName = "MyFunction";
$foo->$funcName();
Static Methods
class Bar
{
static function MyStaticFunction()
{
//code here
}
}
$funcName = "MyStaticFunction";
Bar::$funcName();
While maybe not the case in your situation, when dealing with functions dynamically like this, it is important to check whether the function actually exists and/or is callable.
Alternatively to using Variable Functions, you can use call_user_func which will call the function based on the string name and with provided parameters.
You can use the PHP function call_user_func().
More info here.
You can use call_user_func to do this.
$result = call_user_func($functionToCall, $source, $target)
Documentation: PHP: call_user_func
as far as i know your code should work
here is the link for your refrence

PHP and MagicMethods

I write some class to work with string like in C#.
Here it is:
class String {
private $origin_string = null;
private $result_string = null;
function __construct($string)
{
$this->origin_string = $string;
$this->result_string = $this->origin_string;
}
public function Trim()
{
$this->result_string = Trim($this->result_string);
return $this->result_string;
}
public function StartWith($string)
{
return (substr($this->result_string, 0, strlen($string)) === $string);
}
public function EndWith($string)
{
$endlen = strlen($string);
$strlen = strlen($this->result_string);
return (substr($this->result_string, $strlen - $endlen, $endlen) === $string);
}
public function Contains($string) {
return (strpos($this->result_string, $string) !== false);
}
public function Replace($search, $string) {
$this->result_string = str_replace($search, $string, $this->result_string);
return $this->result_string;
}
public function __invoke($string) {
$this->origin_string = $string;
$this->result_string = $this->origin_string;
return $this;
}
public function __toString()
{
return $this->result_string;
}
public static function Override($string)
{
return new self($string);
}
}
In use:
$s = new String("My custom string");
if ($s->StartWith("My"))
$s->Replace("custom", "super");
print $s; // "My super string"
To correct print my text from object i use magic method __toString().
Question:
Is there a method, the inverse __toString?
That is so we can write:
$s = "new text";
And the line is assigned to variables within the object.
($s - an existing object "String" in the example above.)
An analogue of the method __set, only in relation to the object, not the variable inside it.
While using the __invoke, but it's not quite what I want.
No.
$s = "new text"; assigns the (native PHP) string "new text" to the variable $s. It overwrites whatever $s was before. It does not call any methods on $s if $s is an object.
You'd have to alter the core behavior of PHP to achieve something like that. You'll always have to explicitly call a method on your String object.
The short answer to your direct question is "No, there isn't any way to do that in PHP".
Strings are a primitive data type in PHP, and it doesn't do operator overloading or any other other features you'd need to enable this kind of thing.
But also, because they're a primitive data type, there's no real need to encapsulate them in an object structure like this. PHP's OO capabilities have come a long way in recent versions, but at its heart it still isn't a fully OO language.
In fact, I'd say that what you're doing is counter productive. You're wrapping the concept of a string up into a class that has significantly less functionality than basic PHP. You're writing a whole stack of code in order to do stuff in one line of code that can already be done in one line of code, and you're limiting the ability to do a whole lot more.
For example, you've got Contains() and StartsWith() methods, but they don't deal with regular expressions in any way.
And how are you going to deal with concatenation? And what about embedding variables into strings?
PHP has a lot of string handling functionality (in fact, string handling it's one of its strengths), which your class isn't going to be able to replicate.
I recommend working with the language you've been given, not trying to force it to conform to your syntax ideals.
No, you can't assign directly a value to your object. PHP does not allow operator overloading and this style assignment. You must use the contructor, the invoke or any setter method to assign a new value to your string.
You can write something like this:
$s = 'myclass';
$o = new $s();
or, if you want to 'compile' the new keyword you could do:
$s = '$x = new myclass();';
eval($s);
hope this helps.

PHP: Treat variable like function?

I'd like to use a variable like $GET[name] that always outputs a MySQL-safe version of $_GET[name], even if the value of $GET[name] changes somewhere in the script.
So:
$_GET[name] = "Timmy O'Toole";
echo $GET[name]; // Timmy O\'Toole
$_GET[name] = "Tommy O'Toole";
echo $GET[name]; // Tommy O\'Toole
Is this doable? If not, can you think of any other way that might work that doesn't involve an actual function call? (I'd like to be able to use the variables inside strings and have them automatically evaluate, rather than having to do a whole lot of concatenation.)
Update:
I used a version of mario's solution, and it seems to work:
// Assume $_REQUEST['name'] = "Timmy O'Toole";
class request_safe_vars IMPLEMENTS ArrayAccess {
var $array = array();
function offsetGet($varname) {
return mysql_real_escape_string($_REQUEST[$varname]);
}
function offsetSet($name, $value) { }
function offsetUnset($name) { }
function offsetExists($name) { }
}
$REQUEST = new request_safe_vars();
$_REQUEST['name'] = $_REQUEST['name'].' MODIFIED';
$query = "SELECT id FROM user WHERE name = '{$REQUEST['name']}'";
// Query output:
// SELECT id FROM user WHERE name = 'Timmy O\'Toole MODIFIED'
You don't want to do this.
Rather, the thing you're trying to do -- ensure that the database gets only sane values -- is correct, but the way you're going about it is a bad approach.
Instead of escaping all input as it comes in, you should escape it when you use it by choosing a database adapter that has this functionality built in. PDO is a great example of such a database adapter. PDO uses prepared statements and parameter binding to automatically escape and quote input. Here's an example that binds placeholders at execution time:
$statement = $pdo->prepare('SELECT id FROM users WHERE name = ?');
$statement->execute(array( $_GET['name'] ));
if($statement->rowCount() > 0) {
echo "I found you!";
} else {
echo "You don't exist. :(";
}
Prepared statements with placeholders and binding is the most sane and safe way to ensure that SQL is safe from attack.
That's doable with an object that implements ArrayAccess. By turning $GET into an object you can have a magic offsetSet and offsetGet method which can accomplish this.
class safe_vars IMPLEMENTS ArrayAccess {
var $array = array();
function offsetGet($varname) {
return mysql_real_escape_string($this->array[$varname]);
}
function offsetSet($name, $value) {
$this->array[$name] = $value;
}
function offsetUnset($name) { }
function offsetExists($name) { }
}
This is how you would use it:
$GET = new safe_vars();
$GET["name"] = "Timmy O'Toole";
echo $GET["name"]; // Timmy O\'Toole
I actually have something similar (but never implemented the set part) which specifically works on $_GET (as listed in your question). http://sourceforge.net/p/php7framework/svn/60/tree/trunk/php7/input.php?force=True - It can be configured to apply the sql filter per default for example. Though that approach feels a bit like magic_quotes even if it uses the correct escaping function.
First off, put quotes around 'name' unless you purposely define it as a constant.
Another suggestion would be to use a DB wrapper class such as PDO, mysqli, or your own, and use prepared statements and have the input escaped for you. This has the benefit of escaping data at the last possible time, which is optimal. Either that or you can create a very simple wrapper function, e.g.
function get($key) {
return isset($_GET[$key]) : mysql_real_escape_string($_GET[$key]) : null;
}
The problem with defining a class (unless you use it only statically) is that this strips $_GET of its superglobal status and you are forced to use either globals (evil) or pass all get arguments to local closures.

Find the name of a calling var

Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"

Emulating a value type structure class in PHP

Is there any way to emulate a structure class in PHP? ie a class which passes by value and not by reference, so it can still be type hinted...
And if so, what different techniques could be used? What's the best technique?
If this is possible you could obviously create a fully type safe layer for PHP, are there such layers? Has anyone had any experience with this?
Objects are always passed by reference. The only way to make them pass as a copy is to explicitly use the clone keyword (yes, everywhere).
My recommendation would be to use an array, which are value types and thus always copied. Since you can use it as an associative array (eg string -> value), it might as well be an object. The downside is, of course, you can't use methods (but that's like a struct so you may be happy with this). There is no way to enforce type safety, however.
But with all your requirements it sounds like PHP isn't your kind of language, to be honest.
I think the easiest way is to do it like java does - have your value classes be immutable, and let all "modification" methods return a new object instead.
I don't think you can achieve that goal, only with PHP code.
You have no control on how PHP function handle parameters, and I don't see how you could make sure everything is handled the way you want, without having to change the (lower-level) code in the PHP binary and modules.
It would be pretty cool, though :)
I was playing around with anonymous's suggestion to make any mutations of the object return a new object, and this works, but it's awkward.
<?php
class FruityEnum {
private $valid = array("apple", "banana", "cantaloupe");
private $value;
function __construct($val) {
if (in_array($val, $this->valid)) {
$this->value = $val;
} else {
throw new Exception("Invalid value");
}
}
function __set($var, $val) {
throw new Exception("Use set()!!");
}
function set(FruityEnum &$obj, $val) {
$obj = new FruityEnum($val);
}
function __get($var) { //everything returns the value...
return $this->value;
}
function __toString() {
return $this->value;
}
}
And now to test it:
function mutate(FruityEnum $obj) { // type hinting!
$obj->set($obj, 'banana');
return $obj;
}
$x = new FruityEnum('apple');
echo $x; // "apple"
$y = mutate($x);
echo $x // still "apple"
. $y // "banana"
It works, but you have to use a strange way to change the object:
$obj->set($obj, 'foo');
The only other way I could think to do it would be to use the __set() method, but that was even worse. You had to do this, which is bloody confusing.
$obj = $obj->blah = 'foo';
In the end, it's probably easier to make the variables private and provide no mutators, so the only way to change a variable's "enum" value would be to create a new one:
echo $obj; // "banana"
$obj = new FruityEnum("cantaloupe");

Categories