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)
I'm asking this question because I'm still not quite sure if filter $_GET variable is enough to prevent mysql injection, so at first I have a filter function
function filter_url($url)
{
if (is_array($url))
{
foreach ($url as $key => $value)
{
// recurssion
$url[$key] = filter_url($value);
}
return $url;
}
else
{
// remove everything except for a-ZA-Z0-9_.-&=
$url = preg_replace('/[^a-zA-Z0-9_\.\-&=]/', '', $url);
return $url;
}
}
I have $_GET=filter_url($_GET); everytime before I call
$filter_case =isset($_GET['product_ID'])?"and product_ID={$_GET['product_ID']}":"";
Do I need to do $mysqli->real_escape_string($_GET['product_ID']) ? If I still have to imply it, what kind of sql injection will overpass my query method?
Besides, is it important to do $mysqli->real_escape_string($_SESSION['member_ID']) that I'm thinking of is anyone possible to manipulate his $_SESSION variable?
This is essentially wrong question to ask.
You need $mysqli->real_escape_string when adding a string literal into SQL query. In such a case you need this function regardless of whatever string source or validation. In any other case (ie string goes not in query or not as SQL string) this function going to be absolutely useless.
This is why it is essential to use prepared statements, either native or emulated.
My current way:
class A {
public function function_b($myint) {
if (!is_numeric($myint)) return false;
// code ...
}
}
I would like to abandon the function is_numeric() like this:
public function function_b(Integer $myint) {
// code ...
}
It works with arrays like this:
public function function_c(Array $arr) {
// only executes following code if $arr is an array / instance of Array!
}
Note: the function has to return false if the value isn't a number (int)! I don't want to cast it.
How would you short my current code? Thanks in advance!
You can't force strict types in function prototypes in PHP inherently, because it's not a strictly typed language. PHP is a weakly typed language and trying to go against the grain will only hurt you in many situations. Also, is_numeric does not guarantee that your value is of type int (for what it's worth).
What you can do is analyze your need for why you think this approach is necessary in the first place and decide on how to best implement this without creating potential for bugs.
For example, take the following scenario where what your method expects is an ID for a database query.
class MyClass {
public function getUser($id) {
if (!is_int($id)) {
throw new Exception("Invalid argument supplied. Expecting (int), but argument is of type (" . gettype($id) . ").");
}
// Otherwise continue
$db = new PDO($dsn);
$stmt = $db->prepare("SELECT username FROM users WHERE user_id = ?");
$stmt->execute(array($id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
$MyObject = new MyClass;
$result = $MyObject->getUser($_POST['id']);
/* The problem here is $_POST will always be of type string. */
What this should tell you is that it makes no sense to force type checking here since PHP will have done the right thing for you had you just let it alone.
The question you need to be asking yourself is not "How do I force strict typing?", but rather "Why would I need to force strict typing at all?".
You should look into typecasting:
http://php.net/manual/en/language.types.type-juggling.php#language.types.typecasting
Just use (int) when accessing the value to typecast it to an integer.
You could just typecast it:
public function function_b($myint) {
$myint = (int) $myint;
}
Or better yet add a public setter to class A which will do it for you every time you set the value:
class A
{
public function setMyInt($myInt)
{
$this->myInt = (int) $myInt;
}
}
-- Update (based on comment) --
class A
{
public function doSomethingWithAnArray(array $array)
{
....
}
}
Notice the keyword array in the signature of the doSomethingWithAnArray method, now if you don't pass an array to this function PHP will throw a fatal error and cease code execution. This is known as typehinting, and can be applied to objects as well.
function needsInteger($int) {
if (((int) $int) != $int) return false;
// ...
}
The advantage here is that you can still accept loosely typed parameters, but the non-strict equality check against the cast value will yield an acceptable result.
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"
I have the following constructor:
public function __construct(){
foreach($_GET as $key=>$value){
$_GET[$key] = addslashes($value);
}
$this->get = $_GET;
}
and it's used like so:
$app->get['id']
Where 'id' is the parameter being passed through the URL.Is there a good way to sanitize all the data through the constructor?
A slightly shorter way to do this:
public function __construct(){
$this->get = array_map('mysql_real_escape_string', $_GET);
}
Why are you doing this? To prevent SQL injection?
Preventing injection should be done at the query-building level, and should most definitely be done with a more relevant function like mysql_real_escape_string, which will catch all odd cases, not just quotes. What you are doing here is no better than the infamous magic quotes functionality that has since been removed from PHP.
If you know the type of variable you're expecting you could cast it to the desired type such as
$this->id = (int)$app->get['id']; //forces type to be integer