Restricting variable access - php

I need to have a variable that only one function can write (let's call that function a) and that only one other function can read (let's call that function b). Is that possible?

You could use a static variable:
function foo($val=null) {
static $var = null;
if (!is_null($var)) $var = $val;
return $val;
}
Here $var is only visible inside the function foo and is maintained throughout multiple calls:
foo(123);
echo foo(); // 123
foo(456);
echo foo(); // 456
Or use a class with a private member and access/modify it with public methods:
class A {
private $var;
public function setVar($val) {
$this->var = $val;
}
public function getVar() {
return $this->var;
}
}
With this the private member var is only visible to a particular instance of this class:
$obj1 = new A();
$obj1->setVar(123);
$obj2 = new A();
$obj2->setVar(456);
echo $obj1->getVar(); // 123
echo $obj2->getVar(); // 456
If you make the member static, then there is just one for the class instead of for each instance:
class A {
private static $var;
public function setVar($val) {
self::$var = $val;
}
public function getVar() {
return self::$var;
}
}
$obj1 = new A();
$obj1->setVar(123);
$obj2 = new A();
$obj2->setVar(456);
echo $obj1->getVar(); // 456
echo $obj2->getVar(); // 456

You can use a static abstract class.
abstract class Settings
{
private static var $_settings = array();
public static function get($key,$default = false)
{
return isset(self::$_settings[$key]) ? self::$_settings[$key] : $default;
}
public static function set($key,$value)
{
self::$_settings[$key] = $value;
}
}
Example Usage:
Settings::set('SiteName',`SomeResult`);
echo Settings::get('SiteName');

Since 5.3.0, you can use anonymous functions as closures. The advantage here, is that you can hold on to b... which is returned by a... and fire it off when you're ready:
<?php
function a()
{
// Only a() can write to $myVar
$myVar = 42;
$b = function() use ($myVar)
{
// $b can read $myVar
// no one else can
return $myVar;
};
return $b;
}
// get $b
$test = a();
// use $b
echo $test();
?>
Another solution before 5.3.0, but here a has to fire b which may not be that practical:
You can simply create an internal variable and pass it as an argument. You can do this inside a class, or just inside simple functions:
function a()
{
// ...
// Write the variable that
// only this function can write to
$thisVar = 1;
b($thisVar);
//...
}
function b($myVar)
{
// ...
// Do stuff w $myVar, a copy of $thisVar
// Changing $myVar has no effect on $thisVar
//
}

Do you mean friend functions? Because I'd love to be able to do that. So far I haven't found an easy way though (although you could try using Reflection, but that seems like way to much effort).
For me, it usually hasn't been an issue of maintaining data integrity / encapsulation, but of keeping the list of public methods (which is kinda like a class's API) free of clutter. A perfect framework should be easy to use, have obvious function names etc etc etc. Methods intended for use by a single other method really mess things up. The "solution" I've taken to is prefixing those function names by one or two underscores and writing "intended for internal use only" or something to that extent in the comments.

Related

Class variables holding a function in PHP

PHP allows for variables to hold functions like so:
$f = function($a,$b) {
print "$a $b";
};
$f("Hello","World!"); //prints 'Hello World!'
This works just fine for me. I'm trying to pass a function into a class and set an instance variable to hold that function but with little luck:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print $this->distanceFunc(1,7); //exceptions and errors abound
}
}
$func = function($a,$b) {
return abs($a-$b);
}
$c = new Clusterer($func);
Am I doing something wrong here? The error is that the function doesn't exist so my guess currently is that it looks for a class function with that name (which there isn't one) and then gives up rather than looking for variables as well... how can I make it view the $this->distanceFunc as a variable?
EDIT:
So after the advice from the answers below, I found a solution which was the make a function to wrap the invocation. For example my class is now:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print $this->distanceFunc(1,7); //exceptions and errors abound
}
private function distanceFunc($a,$b) {
$holder = $this->distanceFunc;
return $holder($a,$b);
}
}
$func = function($a,$b) {
return abs($a-$b);
}
$c = new Clusterer($func);
and this works great. Php looks for functions first and can only tell if it is a variable by context I guess is the moral of this story.
Your code doesn't work because PHP interprets $this->distanceFunc(1,7) as a class method, but you can do the following:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print call_user_func_array($this->distanceFunc, array(1, 7));
// print $this->distanceFunc(1,7); //exceptions and errors abound
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
http://sandbox.onlinephpfunctions.com/code/cdc1bd6bd50f62d5c88631387ac9543368069310
In PHP, methods and properties of an object occupy separate namespaces. This is different from JavaScript, for example, where foo.bar = function() {} is a perfectly valid way of defining a method.
Consequently, $this->distanceFunc(1,7); looks for a method named distanceFunc on the current class, and the classes it inherits from, but never looks for the property which you happen to have given the same name.
One solution is to force PHP to look up a property, then execute it, e.g. $foo = $this->distanceFunc; $foo(1,7) or call_user_func($this->distanceFunc, 1, 7)
Another would be to define the magic method __call on your class, which gets run whenever a non-existent method is referenced. Something like this ought to work (I don't have an easy way to testright now):
function __call($func, $args) {
if ( property_exists($this, $func) && is_callable($this->$func) ) {
return call_user_func_array($this->$func, $args);
}
}
Note that this still isn't the same as a real method, for instance in terms of access to private properties.
It looks like you're going for a strategy pattern here. IE you want to be able to inject different methods for calculating distance? If so there is a more "sane" way to do it.
You can define an interface to the classes you will use to store the strategy method ensuring that the class will always have the method calculate() for example which would be your distance calculation function. Then in the constructor of your Clusterer class, type check against the interface in the parameter and call calculate() on the object passed in.
Looks like this:
interface Calculateable
{
public function calculate();
}
class MyDistanceCalculator implements Calculateable
{
public function calculate()
{
// Your function here
}
}
class Clusterer
{
protected $calc;
public function __construct(Calculateable $calc)
{
$this->calc = $calc;
$this->calc->calculate();
}
}
$myClusterer = new Clusterer(new MyDistanceCalculator());
Because you defined an interface, any object you pass in will have the calculate() function
In HHVM, you can do this:
<?php
class Foo
{
public function __construct()
{
$this->bar = function() { echo "Here\n"; };
($this->bar)();
}
}
new Foo();
But it's not yet supported in PHP. But, it will be in PHP 7 (there will be no release named PHP 6).
PHP doesn't have first class functions. In JavaScript if you returned a function you could do this: myFunctionThatReturnsAFunction()(1,2), but not in PHP.
<?php
class Clusterer {
private $distanceFunc;
public function __construct(Closure $f) {
$this->distanceFunc = $f;
}
public function getDistFunc()
{
return $this->distanceFunc;
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
$a = $c->getDistFunc();
echo $a(1,2);
Take a look at call_user_func
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print call_user_func($this->distanceFunc, 1, 7); //works too ;)
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
Don't ask me what is the difference, but it works the way you want (One of the reasons i hate this language)

Get a static property of an instance

If I have an instance in PHP, what's the easiest way to get to a static property ('class variable') of that instance ?
This
$classvars=get_class_vars(get_class($thing));
$property=$classvars['property'];
Sound really overdone. I would expect
$thing::property
or
$thing->property
EDIT: this is an old question. There are more obvious ways to do this in newer
PHP, search below.
You need to lookup the class name first:
$class = get_class($thing);
$class::$property
$property must be defined as static and public of course.
From inside a class instance you can simply use self::...
class Person {
public static $name = 'Joe';
public function iam() {
echo 'My name is ' . self::$name;
}
}
$me = new Person();
$me->iam(); // displays "My name is Joe"
If you'd rather not
$class = get_class($instance);
$var = $class::$staticvar;
because you find its two lines too long, you have other options available:
1. Write a getter
<?php
class C {
static $staticvar = "STATIC";
function getTheStaticVar() {
return self::$staticvar;
}
}
$instance = new C();
echo $instance->getTheStaticVar();
Simple and elegant, but you'd have to write a getter for every static variable you're accessing.
2. Write a universal static-getter
<?php
class C {
static $staticvar = "STATIC";
function getStatic($staticname) {
return self::$$staticname;
}
}
$instance = new C();
echo $instance->getStatic('staticvar');
This will let you access any static, though it's still a bit long-winded.
3. Write a magic method
class C {
static $staticvar = "STATIC";
function __get($staticname) {
return self::$$staticname;
}
}
$instance = new C();
echo $instance->staticvar;
This one allows you instanced access to any static variable as if it were a local variable of the object, but it may be considered an unholy abomination.
classname::property;
I think that's it.
You access them using the double colon (or the T_PAAMAYIM_NEKUDOTAYIM token if you prefer)
class X {
public static $var = 13;
}
echo X::$var;
Variable variables are supported here, too:
$class = 'X';
echo $class::$var;
You should understand what the static property means. Static property or method is not for the objects. They are directly used by the class.
you can access them by
Class_name::static_property_name
These days, there is a pretty simple, clean way to do this.
<?php
namespace Foo;
class Bar
{
public static $baz=1;
//...
public function __toString()
{
return self::class;
}
}
echo Bar::$baz; // returns 1
$bar = new Bar();
echo $bar::$baz; // returns 1
You can also do this with a property in PHP 7.
<?php
namespace Foo;
class Bar
{
public static $baz=1;
public $class=self::class;
//...
}
$bar = new Bar();
echo $bar->class::$baz; // returns 1
class testClass {
public static $property = "property value";
public static $property2 = "property value 2";
}
echo testClass::$property;
echo testClass::property2;

`static` keyword inside function?

I was looking at the source for Drupal 7, and I found some things I hadn't seen before. I did some initial looking in the php manual, but it didn't explain these examples.
What does the keyword static do to a variable inside a function?
function module_load_all($bootstrap = FALSE) {
static $has_run = FALSE
It makes the function remember the value of the given variable ($has_run in your example) between multiple calls.
You could use this for different purposes, for example:
function doStuff() {
static $cache = null;
if ($cache === null) {
$cache = '%heavy database stuff or something%';
}
// code using $cache
}
In this example, the if would only be executed once. Even if multiple calls to doStuff would occur.
Seems like nobody mentioned so far, that static variables inside different instances of the same class remain their state. So be careful when writing OOP code.
Consider this:
class Foo
{
public function call()
{
static $test = 0;
$test++;
echo $test . PHP_EOL;
}
}
$a = new Foo();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3
$b = new Foo();
$b->call(); // 4
$b->call(); // 5
If you want a static variable to remember its state only for current class instance, you'd better stick to a class property, like this:
class Bar
{
private $test = 0;
public function call()
{
$this->test++;
echo $this->test . PHP_EOL;
}
}
$a = new Bar();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3
$b = new Bar();
$b->call(); // 1
$b->call(); // 2
Given the following example:
function a($s){
static $v = 10;
echo $v;
$v = $s;
}
First call of
a(20);
will output 10, then $v to be 20. The variable $v is not garbage collected after the function ends, as it is a static (non-dynamic) variable. The variable will stay within its scope until the script totally ends.
Therefore, the following call of
a(15);
will then output 20, and then set $v to be 15.
Static works the same way as it does in a class. The variable is shared across all instances of a function. In your particular example, once the function is run, $has_run is set to TRUE. All future runs of the function will have $has_run = TRUE. This is particularly useful in recursive functions (as an alternative to passing the count).
A static variable exists only in a
local function scope, but it does not
lose its value when program execution
leaves this scope.
See http://php.net/manual/en/language.variables.scope.php
To expand on the answer of Yang
If you extend a class with static variables, the individual extended classes will hold their "own" referenced static that's shared between instances.
<?php
class base {
function calc() {
static $foo = 0;
$foo++;
return $foo;
}
}
class one extends base {
function e() {
echo "one:".$this->calc().PHP_EOL;
}
}
class two extends base {
function p() {
echo "two:".$this->calc().PHP_EOL;
}
}
$x = new one();
$y = new two();
$x_repeat = new one();
$x->e();
$y->p();
$x->e();
$x_repeat->e();
$x->e();
$x_repeat->e();
$y->p();
outputs:
one:1
two:1
one:2
one:3 <-- x_repeat
one:4
one:5 <-- x_repeat
two:2
http://ideone.com/W4W5Qv
static variable in a function means that no matter how many times you call the function, there's only 1 variable.
<?php
class Foo{
protected static $test = 'Foo';
function yourstatic(){
static $test = 0;
$test++;
echo $test . "\n";
}
function bar(){
$test = 0;
$test++;
echo $test . "\n";
}
}
$f = new Foo();
$f->yourstatic(); // 1
$f->yourstatic(); // 2
$f->yourstatic(); // 3
$f->bar(); // 1
$f->bar(); // 1
$f->bar(); // 1
?>
Inside a function, static means that the variable will retain its value each time the function is called during the life of the page load.
Therefore in the example you've given, if you call a function twice, if it set $has_run to true, then the function would be able to know that it had previously been called because $has_run would still be equal to true when the function starts the second time.
The usage of the static keyword in this context is explained in the PHP manual here: http://php.net/manual/en/language.variables.scope.php

Call private methods and private properties from outside a class in PHP

I want to access private methods and variables from outside the classes in very rare specific cases.
I've seen that this is not be possible although introspection is used.
The specific case is the next one:
I would like to have something like this:
class Console
{
final public static function run() {
while (TRUE != FALSE) {
echo "\n> ";
$command = trim(fgets(STDIN));
switch ($command) {
case 'exit':
case 'q':
case 'quit':
echo "OK+\n";
return;
default:
ob_start();
eval($command);
$out = ob_get_contents();
ob_end_clean();
print("Command: $command");
print("Output:\n$out");
break;
}
}
}
}
This method should be able to be injected in the code like this:
Class Demo
{
private $a;
final public function myMethod()
{
// some code
Console::run();
// some other code
}
final public function myPublicMethod()
{
return "I can run through eval()";
}
private function myPrivateMethod()
{
return "I cannot run through eval()";
}
}
(this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)
So...
If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:
> $this->myPublicMethod();
But you cannot run successfully the second one:
> $this->myPrivateMethod();
Do any of you have any idea, or if there is any library for PHP that allows you to do this?
Thanks a lot!
Just make the method public. But if you want to get tricky you can try this (PHP 5.3):
class LockedGate
{
private function open()
{
return 'how did you get in here?!!';
}
}
$object = new LockedGate();
$reflector = new ReflectionObject($object);
$method = $reflector->getMethod('open');
$method->setAccessible(true);
echo $method->invoke($object);
EDIT:
Updated to include examples of private function calls with parameters.
As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.
The Closure class
For example we have a class with a private variable and we want to access it outside the class:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
PHP 5.4+
$foo = new Foo;
// Single variable example
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
// Function call with parameters example
$getFooAddABCallback = function() {
// As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6); // Prints 39
As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:
PHP 7+
$foo = new Foo;
// Single variable example
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo); // Prints Foo::Bar
// Function call with parameters example
$getFooAddAB = function() {
return $this->add_ab(...func_get_args());
};
echo $getFooAddAB->call($foo, 33, 6); // Prints 39
The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a very bad (and largely unmaintainable) practice.
EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.
That having been said, you can use Reflection to accomplish this. Instantiate ReflectionClass, call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod.
A code sample (though I haven't tested it, so there may be errors) might look like
$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);
Here's a variation of the other answers that can be used to make such calls one line:
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie
private function _myPrivateMethod()
Then i simply make the function public.
public function _myPrivateMethod()
So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.
If you are able to added a method in the class where the method is defined, you can add method which uses the call_user_method() internally. This works also with PHP 5.2.x
<?php
class SomeClass {
public function callprivate($methodName) {
call_user_method(array($this, $methodName));
}
private function somePrivateMethod() {
echo 'test';
}
}
$object = new SomeClass();
$object->callprivate('somePrivateMethod');
Answer is put public to the method. Whatever trick you are going to do it wouldn't be understandable to fellow developers. For example they do not know that at some other code this function has been accessed as public by looking at the Demo class.
One more thing. that console can access the first method writing a command like:. How can this even be possible? Console can not access demo class functions by using $this.
I guess the reflectionClass is the only alternative if you really want to execute some private methods. Anyhow, if you just need read access to privat or protected properties, you could use this code:
<?php
class Demo
{
private $foo = "bar";
}
$demo = new Demo();
// Will return an object with public, private and protected properties in public scope.
$properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo)));
?>
<?php
$request="email";
$data=[1,2,3,4,5];
$name=new Update($request,$data);
class Update{
private $request;
private $data;
function __construct($request,$data){
$this->request=$request;
$this->data=$data;
if($this->request=='email'){
$this->update_email();
}
else{
echo "Can't do anything";
}
}
private function update_email(){
echo $this->request;
echo '\n';
foreach($this->data as $x){
echo $x."\n";
}
}
}
?>

Reset Class Instance Variables via Method

Does anyone know how to reset the instance variables via a class method. Something like this:
class someClass
{
var $var1 = '';
var $var2 = TRUE;
function someMethod()
{
[...]
// this method will alter the class variables
}
function reset()
{
// is it possible to reset all class variables from here?
}
}
$test = new someClass();
$test->someMethod();
echo $test->var1;
$test->reset();
$test->someMethod();
I know I could simply do $test2 = new SomeClass() BUT I am particularly looking for a way to reset the instance (and its variables) via a method.
Is that possible at all???
You can use reflection to achieve this, for instance using get_class_vars:
foreach (get_class_vars(get_class($this)) as $name => $default)
$this -> $name = $default;
This is not entirely robust, it breaks on non-public variables (which get_class_vars does not read) and it will not touch base class variables.
Yes, you could write reset() like:
function reset()
{
$this->var1 = array();
$this->var2 = TRUE;
}
You want to be careful because calling new someClass() will get you an entirely new instance of the class completely unrelated to the original.
this could be easy done;
public function reset()
{
unset($this);
}
Sure, the method itself could assign explicit values to the properties.
public function reset()
{
$this->someString = "original";
$this->someInteger = 0;
}
$this->SetInitialState() from Constructor
Just as another idea, you could have a method that sets the default values itself, and is called from within the constructor. You could then call it at any point later as well.
<?php
class MyClass {
private $var;
function __construct() { $this->setInitialState(); }
function setInitialState() { $this->var = "Hello World"; }
function changeVar($val) { $this->var = $val; }
function showVar() { print $this->var; }
}
$myObj = new MyClass();
$myObj->showVar(); // Show default value
$myObj->changeVar("New Value"); // Changes value
$myObj->showVar(); // Shows new value
$myObj->setInitialState(); // Restores default value
$myObj->showVar(); // Shows restored value
?>

Categories