I'n just learning PHP by myself, and I have a question, hope you will be able to help.
In fist style
<?php
class Fist_style
{
function method_1()
{
global $a;
return $a + 1;
}
function method_2()
{
global $a;
return $a - 1;
}
function method_3()
{
$call_1 = $this->method_1();
$call_2 = $this->method_2();
}
// In this case, how many times $a was called?
}
In second style
<?php
class Second_style
{
function method_1($a)
{
return $a + 1;
}
function method_2($a)
{
return $a - 1;
}
function method_3()
{
global $a;
//I will call both method_1 and method_2
$call_1 = $this->method_1($a);
$call_2 = $this->method_2($a);
//............
}
// In this case, how many times $a was called
}
?>
The questions are inside my code, and what style will better when develop?
Using globals is very often a recipe for disaster - as many people with experience will be happy to tell you.
The normal way of having state in a class is declaring a class property:
<?
class MyClass
{
public $a;
function __construct($valueForA) {
$this->a = $valueForA;
}
function increment()
{
$this->a += 1;
}
function decrement()
{
$this->a -= 1;
}
function plusminus()
{
$this->increment();
$this->decrement();
}
}
Which can be used like so:
$anInstance = new MyClass(10); // sets a to 10 by calling the __construct method
$anInstance->increment();
echo($anInstance->a); // 11
$anInstance->decrement();
echo($anInstance->a); // 10
Read more about oop in PHP here.
As for the question in your code, the $a is not a method, so it can't be called.
Also, return $a -1; does not change the global $a (not sure if this was the intention).
Edit:
If you have a function increment like
function increment ($var) {
$var = $var - 1;
return $var;
}
then the $var is passed in as a value - if you passed in a 5, php only cares about 5, not the name. Example:
$a = 5;
$incremented = increment($a);
echo($a); // echoes 5;
echo($incremented); //echoes 6
I would suggest reading up on scoping in php.
As PHP manual states
Note: You should never use parentheses around your return variable when returning by reference, as this will not work. You can only return variables by reference, not the result of a statement. If you use return ($a); then you're not returning a variable, but the result of the expression ($a) (which is, of course, the value of $a).
I can not understand why not while the following code examples will give the same result.
The code with return $var:
<?php
function a(&$a) {
$a .= "c";
return $a;
}
$b = "b";
echo a($b);
echo $b;
?>
The code with return ($var):
<?php
function a(&$a) {
$a .= "c";
return ($a);
}
$b = "b";
echo a($b);
echo $b;
?>
The examples you show are Passing by Reference, where you pass a reference of a variable to a function. The quote from the manual is about Returning References of a variable in a function.
Just like you can't pass an expression by reference, you can't return an expression by reference, and wrapping a variable in () turns it in to an expression.
Passing a Reference
function a(&$b) { $b = 1; }
$x = 0;
a($x);
echo $x; // echos 1, because a reference to $x was changed
However a(abs($x)); or even a( ($x) ); generates:
Strict Standards: Only variables should be passed by reference
Returning a Reference
class a {
public $c = 0;
public function &b() { return $this->c; }
}
$a = new a;
$x = &$a->b();
$a->c = 1;
echo $x; // echos 1, because $x is a reference to $a->c that was changed
However, return ( $this->c ); generates:
Notice: Only variable references should be returned by reference
The example you give is not about returning references, but is an example of passing references.
function myfunc(&$arg) {
// here $arg has been passed by reference, nothing to do with the docs you quoted
}
The docs are about this:
function & myfunc($arg) {
// here you create your $result using $arg and whatever
return $result; // this will work
return ($result); // this will NOT
}
// and how you use it
$res =& myfunc(1);
You're modifying the variable, because it's passed by reference. But then you're setting it to the value that's returned by the function. That's why you're getting the same result.
When modifying a variable by reference, you don't need to return it. Your function will still have the same result if you write it like this:
function a(&$a) {
$a .= "c";
}
When you pass any value to the function, php copy the value and return a copy, not the variable you passed to the function. So if you want to change value and don't want to return anything from the function you need to declare, functions argument as reference - it means that any variable that you will pass to the function wont be copied by php and manipulation inside the function will change variable outside the function, for example:
$var = 1;
//not reference function
function notReference($argument)
{
$argument++;
}
notReference($var);
echo $var; // you will get 1
function reference(&$argument)
{
$argument++;
}
reference($var)
echo $var; // you will get 2,
So we call some function in PHP:
do_something('foodabaa');
function do_something($subject)
{
static $pattern = '~foo~';
return preg_replace($pattern, 'bar', $subject);
}
Is the replacement value bar static, or is it dynamic so each call to the function reinitializes it?
By all means add info about other programming languages besides PHP.
From PHP documentation (Example #5):
function test()
{
static $a = 0;
echo $a."\n\r";
$a++;
}
Now, $a is initialized only in first call of function and every time
the test() function is called it will print the value of $a and
increment it.
So if you will call it twice:
test();
test();
Return will be:
0
1
Lets back to your example. There is same situation, $pattern will be initialized just once.
Inside C/C++
void foo()
{
static int a = 0;
printf("%d", a);
x++;
}
int main()
{
foo();
foo();
return 0;
}
Output will be:
0
1
That's the common behavior in many languages which are using static variables.
class Test {
private $arr;
function __construct() {
$this->arr = array('test');
}
function getArr() {
return $this->arr;
}
}
$a = new Test();
$b = $a->getArr();
$b[0][0] = 'a';
$s = $a->getArr();
echo $s[0]
Why does this echo test instead of aest? Does PHP copy the array and the contents of the array when returning it? How do I get an array in which I can change the strings and have it reflected in the object?
By returning and assigning by reference:
class Test {
//...
function &getArr() {
return $this->arr;
}
}
$a = new Test();
$b =& $a->getArr();
$b[0][0] = 'a';
$s = $a->getArr();
echo $s[0];
Does PHP copy the array and the contents of the array when returning it?
From the point of view of the programmer, it works as if returning would copy the value, except when returning by reference. In terms of implementation, there are optimizations that avoid this happens, as long as it has no impact in the behavior of the script.
In PHP, I am able to use a normal function as a variable without problem, but I haven't figured out how to use a static method. Am I just missing the right syntax, or is this not possible?
(EDIT: the first suggested answer does not seem to work. I've extended my example to show the errors returned.)
function foo1($a,$b) { return $a/$b; }
class Bar
{
static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
// WORKS FINE:
$fn = foo1;
print $fn(1,1);
// WORKS FINE:
print self::foo2(2,1);
print Bar::foo2(3,1);
// DOES NOT WORK ... error: Undefined class constant 'foo2'
//$fn = self::foo2;
//print $fn(4,1);
// DOES NOT WORK ... error: Call to undefined function self::foo2()
//$fn = 'self::foo2';
//print $fn(5,1);
// DOES NOT WORK ... error: Call to undefined function Bar::foo2()
//$fn = 'Bar::foo2';
//print $fn(5,1);
}
}
$x = new Bar();
$x->UseReferences();
(I am using PHP v5.2.6 -- does the answer change depending on version too?)
PHP handles callbacks as strings, not function pointers. The reason your first test works is because the PHP interpreter assumes foo1 as a string. If you have E_NOTICE level error enabled, you should see proof of that.
"Use of undefined constant foo1 - assumed 'foo1'"
You can't call static methods this way, unfortunately. The scope (class) is relevant so you need to use call_user_func instead.
<?php
function foo1($a,$b) { return $a/$b; }
class Bar
{
public static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
$fn = 'foo1';
echo $fn(6,3);
$fn = array( 'self', 'foo2' );
print call_user_func( $fn, 6, 2 );
}
}
$b = new Bar;
$b->UseReferences();
In php 5.2, you can use a variable as the method name in a static call, but to use a variable as the class name, you'll have to use callbacks as described by BaileyP.
However, from php 5.3, you can use a variable as the class name in a static call. So:
class Bar
{
public static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
$method = 'foo2';
print Bar::$method(6,2); // works in php 5.2.6
$class = 'Bar';
print $class::$method(6,2); // works in php 5.3
}
}
$b = new Bar;
$b->UseReferences();
?>
You could use the full name of static method, including the namespace.
<?php
function foo($method)
{
return $method('argument');
}
foo('YourClass::staticMethod');
foo('Namespace\YourClass::staticMethod');
The name array array('YourClass', 'staticMethod') is equal to it. But I think the string may be more clear for reading.
In PHP 5.3.0, you could also do the following:
<?php
class Foo {
static function Bar($a, $b) {
if ($a == $b)
return 0;
return ($a < $b) ? -1 : 1;
}
function RBar($a, $b) {
if ($a == $b)
return 0;
return ($a < $b) ? 1 : -1;
}
}
$vals = array(3,2,6,4,1);
$cmpFunc = array('Foo', 'Bar');
usort($vals, $cmpFunc);
// This would also work:
$fooInstance = new Foo();
$cmpFunc = array('fooInstance', 'RBar');
// Or
// $cmpFunc = array('fooInstance', 'Bar');
usort($vals, $cmpFunc);
?>
Coming from a javascript background and being spoiled by it, I just coded this:
function staticFunctionReference($name)
{
return function() use ($name)
{
$className = strstr($name, '::', true);
if (class_exists(__NAMESPACE__."\\$className")) $name = __NAMESPACE__."\\$name";
return call_user_func_array($name, func_get_args());
};
}
To use it:
$foo = staticFunctionReference('Foo::bar');
$foo('some', 'parameters');
It's a function that returns a function that calls the function you wanted to call. Sounds fancy but as you can see in practice it's piece of cake.
Works with namespaces and the returned function should work just like the static method - parameters work the same.
This seems to work for me:
<?php
class Foo{
static function Calc($x,$y){
return $x + $y;
}
public function Test(){
$z = self::Calc(3,4);
echo("z = ".$z);
}
}
$foo = new Foo();
$foo->Test();
?>
In addition to what was said you can also use PHP's reflection capabilities:
class Bar {
public static function foo($foo, $bar) {
return $foo . ' ' . $bar;
}
public function useReferences () {
$method = new ReflectionMethod($this, 'foo');
// Note NULL as the first argument for a static call
$result = $method->invoke(NULL, '123', 'xyz');
}
}
"A member or method declared with static can not be accessed with a variable that is an instance of the object and cannot be re-defined in an extending class"
(http://theserverpages.com/php/manual/en/language.oop5.static.php)