I dont know how to predefine one of the variables in function.
<?php
$number = 3;
function test($num, $num2 = $number) {
$result = "num = ".$num." and num2 = ".$num2;
return $result;
}
echo test(1);
?>
It always prints out:
Fatal error: Constant expression contains invalid operations in C:\xampp\htdocs\php\index.php on line 3
It's better to use it like this:
function test($num, $num2 = 3) {/**/}
But, if you really need it, you can define a constant:
const NUMBER = 3;
function test($num, $num2 = NUMBER)
{
$result = "num = $num and num2 = $num2";
return $result;
}
echo test(1); // returns "num = 1 and num2 = 3"
And the 3d option, if you want to use some dynamic variable:
$number = 3;
function test($num, $num2)
{
$result = "num = $num and num2 = $num2";
return $result;
}
echo test(1, $number); // returns "num = 1 and num2 = 3"
Or you can use a class:
class Test
{
protected $number;
public function __construct($number)
{
$this->number = $number;
}
public function test($num)
{
$result = "num = $num and num2 = $this->number";
return $result;
}
}
$test = new Test(3);
echo $test->test(1); // returns "num = 1 and num2 = 3"
If you want assingn a default value to a param you must use a value (a constant expression) not a var (variable expression)
function test($num, $num2 = 3 )
Related
I am working on some old php code. in dev envioronment and error_reporting turned on to E_ALL | E_STRICT i get Notice: Undefined offset: 4 in /home/pgnetdev/www/PGNet/php-includes/base_classes.inc on line 545
the offending php class is
<?php
class CMap
{
var $m_aData;
var $m_aKeys;
var $m_iNumItems;
var $m_iCurrentDatumIndex;
function CMap()
{
$this->m_aData = array();
$this->m_aKeys = array();
$this->m_iNumItems = 0;
$this->m_iCurrentDatumIndex = 0;
}
function Add($strKey, & $clDatum)
{
if ($this->Contains($strKey))
return false;
$this->m_aKeys[$strKey] = $strKey;
$this->m_iNumItems++;
$this->m_aData[$strKey] = & $clDatum;
return true;
}
function &First()
{
if ($this->m_iNumItems <= 0)
return null;
sort($this->m_aKeys);
$this->m_iCurrentDatumIndex = 0;
return $this->m_aData[$this->m_aKeys[0]];
}
//line 545 in this method
function &Next()
{
fwrite(STDERR, "+[NEXT]: {$this->m_iCurrentDatumIndex} >= {$this->m_iNumItems}\n"); //not deployed
if ($this->m_iCurrentDatumIndex >= $this->m_iNumItems)
{
fwrite(STDERR, "-[NEXT]: returning null\n");// not deployed
return null;
}
fwrite(STDERR, "-[NEXT]: returning value\n"); //not deployed
return $this->m_aData[$this->m_aKeys[++$this->m_iCurrentDatumIndex]];// line 545
}
function &Find($strKey)
{
if (array_key_exists($strKey, $this->m_aData))
return $this->m_aData[$strKey];
return null;
}
function Contains($strKey)
{
return array_key_exists($strKey, $this->m_aData);
}
function Items()
{
return $this->m_iNumItems;
}
}
my tests for it are
<?php
error_reporting(E_ALL | E_STRICT);
require_once '../PGNet/php-includes/base_classes.inc';
class CMapTest extends PHPUnit_Framework_TestCase
{
public function testItemsReturnsNumberOfItemsAdded()
{
$map = new CMap();
$var = 1;
$this->assertEquals(0, $map->Items(), 'No Items, Zero Count expected');
$map->Add("KEY", $var);
$this->assertEquals(1, $map->Items(), 'Item just added, should have count 1');
}
public function testContainsReturnsTrueIfMapContainsKey()
{
$map = new CMap();
$var = 1;
$this->assertFalse($map->Contains("KEY"), 'No Items, No KEYS');
$map->Add("KEY", $var);
$this->assertTrue($map->Contains("KEY"), 'Item just added, should a key');
}
public function testFindReturnsNullIfMapDoesntContainsKey()
{
$map = new CMap();
$var = 1;
$map->Add("KEY", $var);
$actual = $map->Find("NO_KEY");
$this->assertEquals(null, $actual, 'no key no value... NULL is expected here');
}
public function testFindReturnsValueIfMapContainsKey()
{
$map = new CMap();
$var = 1;
$map->Add("KEY", $var);
$actual = $map->Find("KEY");
$this->assertEquals($var, $actual, 'has key finds value... var is expected here');
}
public function testAddReturnsFalseIfKeyIsAlreadyAdded()
{
$map = new CMap();
$var1 = 1;
$var2 = 2;
$willBeTrue = $map->Add("KEY", $var1);
$willBeFalse = $map->Add("KEY", $var2);
$this->assertTrue($willBeTrue, "first key added should always be true");
$this->assertFalse($willBeFalse, "key already exists so you cant replace it");
}
public function testFirstReturnsNullWhenNoItemsAdded()
{
$map = new CMap();
$actual = $map->First();
$this->assertEquals(null, $actual, 'no items added, returns false');
}
public function testFirstReturnsFirstSortedValue()
{
$map = new CMap();
$var1 = 1;
$var2 = 2;
$map->Add("B", $var2);
$map->Add("A", $var1);
$actual = $map->First();
$this->assertEquals($var1, $actual, 'keys are sorted then first one is grabbed');
}
public function testNextReturnsNullIfOnlySingleItemAdded()
{
$map = new CMap();
$var1 = 1;
$map->Add("A", $var1);
$actual = $map->First();
$this->assertEquals($var1, $actual, 'keys are sorted then first one is grabbed');
$this->assertEquals(null, $map->Next());
}
public function testNextReturnsNullAfterAllItemsAreIteratedThrough()
{
fwrite(STDERR, "+[testNextReturnsNullAfterAllItemsAreIteratedThrough]\n");
$map = new CMap();
$var1 = 1;
$var2 = 2;
$map->Add("B", $var2);
$map->Add("A", $var1);
$actual = $map->First();
$loopCount = 0;
try
{
for($actual = $map->First(); $actual != null; $actual = $map->Next())
{
$this->assertNotNull($actual);
$loopCount++;
}
}
catch (Throwable $th)
{
fwrite(STDERR, "-[testNextReturnsNullAfterAllItemsAreIteratedThrough]:WTH\n");
$this->assertFalse(true, $th->getMessage());
}
$this->assertEquals(2, $loopCount, "the for loop should work");
fwrite(STDERR, "-[testNextReturnsNullAfterAllItemsAreIteratedThrough]\n");
}
}
The last test in here is what I was really puzzled why it isn't breaking or throwing or anything. the console output for that is
$ phpunit ../PGNetTests/tests/unitTests/
PHPUnit #package_version# by Sebastian Bergmann.
.......................................................+[NEXT]: 0 >= 1
-[NEXT]: returning value
.+[testNextReturnsNullAfterAllItemsAreIteratedThrough]
+[NEXT]: 0 >= 2
-[NEXT]: returning value
+[NEXT]: 1 >= 2
-[NEXT]: returning value
-[testNextReturnsNullAfterAllItemsAreIteratedThrough]
.... 60 / 88
..........................+[NEXT]: 0 >= 1
-[NEXT]: returning value
..
Time: 0 seconds, Memory: 4.25Mb
OK (88 tests, 326 assertions)
like I would expect to either get the same message in the output as I do in production or to at least a thrown exception or even a -[NEXT] return null but i get nothing but passing tests and I don't know why. Why???
I've created a memoized function of the recursive version of fibonacci.
I use this as an example for other kinds of functions that would use memoization.
My implementation is bad since if I include it in a library, that means that the global variable is still seen..
This is the original recursive fibonacci function:
function fibonacci($n) {
if($n > 1) {
return fibonacci($n-1) + fibonacci($n-2);
}
return $n;
}
and I modified it to a memoized version:
$memo = array();
function fibonacciMemo($n) {
global $memo;
if(array_key_exists($n, $memo)) {
return $memo[$n];
}
else {
if($n > 1) {
$result = fibonacciMemo($n-1) + fibonacciMemo($n-2);
$memo[$n] = $result;
return $result;
}
return $n;
}
}
I purposely didn't use the iterative method in implementing fibonacci.
Is there any better ways to memoize fibonacci function in php? Can you suggest me better improvements? I've seen func_get_args() and call_user_func_array as another way but I can't seem to know what is better?
So my main question is: How can I memoize fibonacci function in php properly? or What is the best way in memoizing fibonacci function in php?
Well, Edd Mann shows an excellent way to implement a memoize function in php in His post
Here is the example code (actually taken from Edd Mann's post):
$memoize = function($func)
{
return function() use ($func)
{
static $cache = [];
$args = func_get_args();
$key = md5(serialize($args));
if ( ! isset($cache[$key])) {
$cache[$key] = call_user_func_array($func, $args);
}
return $cache[$key];
};
};
$fibonacci = $memoize(function($n) use (&$fibonacci)
{
return ($n < 2) ? $n : $fibonacci($n - 1) + $fibonacci($n - 2);
});
Notice that the global definition it's replaced thanks to function clousure and PHP's first-class function support.
Other solution:
You can create a class containing as static members: fibonnacciMemo and $memo. Notice that you don't longer have to use $memo as a global variable, so it won't give any conflict with other namespaces.
Here is the example:
class Fib{
//$memo and fibonacciMemo are static members
static $memo = array();
static function fibonacciMemo($n) {
if(array_key_exists($n, static::$memo)) {
return static::$memo[$n];
}
else {
if($n > 1) {
$result = static::fibonacciMemo($n-1) + static::fibonacciMemo($n-2);
static::$memo[$n] = $result;
return $result;
}
return $n;
}
}
}
//Using the same method by Edd Mann to benchmark
//the results
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000249
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000016 (now with memoized fibonacci)
//Cleaning $memo
Fib::$memo = array();
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000203 (after 'cleaning' $memo)
Using this, you avoid the use of global and also the problem of cleaning the cache. Althought, $memo is not thread save and the keys stored are no hashed values.
Anyways, you can use all the php memoize utilites such as memoize-php
i think... this should to to memoize a fibonacci:
function fib($n, &$computed = array(0,1)) {
if (!array_key_exists($n,$computed)) {
$computed[$n] = fib($n-1, $computed) + fib($n-2, $computed);
}
return $computed[$n];
}
some test
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000068
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000005
//Cleaning $arr
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000039
Another solution:
function fib($n, &$memo = []) {
if (array_key_exists($n,$memo)) {
return $memo[$n];
}
if ($n <=2 ){
return 1;
}
$memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
return $memo[$n];
}
Performance:
$start = microtime(true);
fib(100);
echo sprintf("%f\n", microtime(true) - $start);
// 0.000041
This's an implementation of memoize a fibonacci:
function fib(int $n, array &$memo = [0,1,1]) : float {
return $memo[$n] ?? $memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
}
Call
echo fib(20); // 6765
function fibMemo($n)
{
static $cache = [];
//print_r($cache);
if (!empty($cache[$n])) {
return $cache[$n];
} else {
if ($n < 2) {
return $n;
} else {
$p = fibMemo($n - 1) + fibMemo($n - 2);
$cache[$n] = $p;
return $p;
}
}
}
echo fibMemo(250);
I'm trying to do something like the following:
// assume $f is an arg to the wrapping function
$self = $this;
$func = function() use($f, $ctx, $self){
$self->remove($func, $ctx); // I want $func to be a reference to this anon function
$args = func_get_args();
call_user_func_array($f, $args);
};
Is it possible to reference the function assigned to $func from with the same function?
Try doing
$func = function() use (/*your variables,*/ &$func) {
var_dump($func);
return 1;
};
http://codepad.viper-7.com/cLd3Fu
Yes you can
See this example: http://php.net/manual/en/functions.anonymous.php#105564
Code from example:
<?php
$fib = function($n) use(&$fib) {
if($n == 0 || $n == 1) return 1;
return $fib($n - 1) + $fib($n - 2);
};
echo $fib(2) . "\n"; // 2
$lie = $fib;
$fib = function(){die('error');};//rewrite $fib variable
echo $lie(5); // error because $fib is referenced by closure
?>
Yes, it is possible if you use a variable by reference. For example:
$func = function($i) use(&$func) {
if ($i <= 0) {
return;
}
echo "Countdown: $i.\n";
$func($i - 1);
};
$func(3);
Is it possible to get those values inside of function and use those outside of function
here is my code:
<?
function expenditure () {
$totalexpenditure = $sum1 + $sum2;
}
function income () {
totalincome = $sum1 + $sum2;
}
$profit = $totalincome - $totalexpenditure;
?>
now my question is how can i get value of totalincome and toatalexpenditure ?
i am learning php alos new in php so please help me guys.
<?
function expenditure ($sum1, $sum2) {
$totalexpenditure = $sum1 + $sum2;
return $totalexpenditure;
}
function income ($sum1, $sum2) {
$totalincome = $sum1 + $sum2;
return $totalincome;
}
$profit = income ($sum1, $sum2) - expenditure($sum1, $sum2) ;
?>
return statement
Your code is wrong, because:
the variables within functions do not have value assigned (you should assign it preferably by function parameters, but another - working, but wrong - solution is making them global variables),
in the example given, $profit will be always 0 (zero).
The solutions are three:
Solution no. 1:
function expenditure ($sum1, $sum2) {
$expenditure = $sum1 + $sum2;
return $expenditure;
}
function income ($sum1, $sum2) {
$income = $sum1 + $sum2;
return $income;
}
And then you can use it like that:
$profit = income(10, 200) - expenditure(20,18);
Solution no. 2:
class Finances {
public $expenditure = 0;
public $income = 0;
public function addExpense($expense) {
$this->expenditure = $this->expenditure + $expense;
return $this;
}
public function addIncome($income) {
$this->income = $this->income + $income;
return $this;
}
public function getProfit() {
return $this->income - $this->expenditure;
}
}
and then you can use it like that:
$my_finances = new Finances();
$my_finances->addExpense(20)->addExpense(18)->addIncome(10)->addIncome(10);
$profit = $my_finances->getProfit();
Solution no. 3: (avoid using!)
function expenditure() {
global $sum1, $sum2;
return $sum1 + $sum2;
}
function income() {
global $sum1, $sum2;
return $sum1 + $sum2;
}
And then you use it like that:
$sum1 = 10;
$sum2 = 200;
$expenditure = expenditure();
$sum1 = 20;
$sum2 = 30;
$income = income();
$profit = $income - $expenditure;
I hope you see, why the Solution no. 3 is such a bad idea (as generally using global variables to pass something to function is bad idea).
This relates to another problem, that you may face at a later stage. What if you wanted to pass 2 variables in a function and change both their values.
$var1 = 22;
$var2 = 15;
function multi2(&$x, &$y){
$x = $x * 2;
$y = $y * 2;
}
multi2($var1, $var2);
print $var1 . ", " . $var2;
You will get this as an output
44, 30
The $x and $y parameters are not a variable themselves, but a reference (defined by &) to the variables passed through, this is helpful if you require to change the values external variables internally.
Link to understand more http://php.net/manual/en/language.references.pass.php
I am having trouble calling a specific function within a class. The call is made:
case "Mod10":
if (!validateCreditCard($fields[$field_name]))
$errors[] = $error_message;
break;
and the class code is:
class CreditCardValidationSolution {
var $CCVSNumber = '';
var $CCVSNumberLeft = '';
var $CCVSNumberRight = '';
var $CCVSType = '';
var $CCVSError = '';
function validateCreditCard($Number) {
$this->CCVSNumber = '';
$this->CCVSNumberLeft = '';
$this->CCVSNumberRight = '';
$this->CCVSType = '';
$this->CCVSError = '';
// Catch malformed input.
if (empty($Number) || !is_string($Number)) {
$this->CCVSError = $CCVSErrNumberString;
return FALSE;
}
// Ensure number doesn't overrun.
$Number = substr($Number, 0, 20);
// Remove non-numeric characters.
$this->CCVSNumber = preg_replace('/[^0-9]/', '', $Number);
// Set up variables.
$this->CCVSNumberLeft = substr($this->CCVSNumber, 0, 4);
$this->CCVSNumberRight = substr($this->CCVSNumber, -4);
$NumberLength = strlen($this->CCVSNumber);
$DoChecksum = 'Y';
// Mod10 checksum process...
if ($DoChecksum == 'Y') {
$Checksum = 0;
// Add even digits in even length strings or odd digits in odd length strings.
for ($Location = 1 - ($NumberLength % 2); $Location < $NumberLength; $Location += 2) {
$Checksum += substr($this->CCVSNumber, $Location, 1);
}
// Analyze odd digits in even length strings or even digits in odd length strings.
for ($Location = ($NumberLength % 2); $Location < $NumberLength; $Location += 2) {
$Digit = substr($this->CCVSNumber, $Location, 1) * 2;
if ($Digit < 10) {
$Checksum += $Digit;
} else {
$Checksum += $Digit - 9;
}
}
// Checksums not divisible by 10 are bad.
if ($Checksum % 10 != 0) {
$this->CCVSError = $CCVSErrChecksum;
return FALSE;
}
}
return TRUE;
}
}
When I run the application - I get the following message:
Fatal error: Call to undefined
function validateCreditCard() in
C:\xampp\htdocs\validation.php
on line 339
any ideas?
class Foo {
// How may I be called?
function bar() {
}
function baz() {
// Use $this-> to call methods within the same instance
$this->bar();
}
function eek() {
// Use self:: to call a function within the same class statically
self::bar();
}
}
// Use [class]:: to call a class function statically
Foo::bar();
// Use [object]-> to call methods of objects
$fooInstance = new Foo();
$fooInstance->bar();
Calling methods statically or as an instance method is not necessarily interchangeable, beware. That's all pretty well covered in the basics of OOP by the way.
Does the class containing the function within which you use the Switch-Case inherit the CreditCardValidationSolution Class....??
My guess would be that you are trying to call the function outside the class without inheriting it.... Maybe you just missed it....
Edit After Reading Comment :
What you need here is "Inheritance"
Take a look at the following links.....
http://www.killerphp.com/tutorials/object-oriented-php/php-objects-page-4.php
http://marakana.com/blog/examples/php-inheritance.html
Hope this helps....