Member and Function Inheritance in PHP - php

I'm still new to PHP and I am having a lot of trouble. I'm used to languages like C,C++, and Java, and this one is kinda confusing me. Basically my problem is that I have the following code:
class File_Reader
{
protected $text;
public function Scan_File (){}
public function Skip_Whitespace(&$current_pos)
{
//skip past whitespace at the start
while (($current_pos < strlen($text) && ($text[$current_pos] == ' ')))
$current_pos++;
}
public function __construct(&$file_text)
{
$text = $file_text;
}
}
class Times_File_Reader extends File_Reader
{
Public Function Scan_File()
{
$errors = array();
$times = array();
$current_time;
$cursor = 0;
$line = 0;
while ($cursor < strlen($text))
{
Skip_Whitespace($cursor);
//....lots more code here...
return $times;
}
}
}
but when I try to run it, it tells me that $time and Skip_Whitespace are both undefined. I don't understand, they should have been inherited. I tried putting an echo command in the File_Reader constructor and it does enter the constructor when I create my Times_File_Reader.
Oh, and for completeness, here is where I declare my Times_File_Reader:
include 'File_Readers.php';
$text = file_get_contents("01_CT.txt");
$reader = new Times_File_Reader($text);
$array = $reader->Scan_File();
I've been searching for an answer for hours to no avail, and deadline is approaching quickly. Any help would be appreciated. Thank you!

I believe that you need to note that you are using the class function by using
$this->Skip_Whitespace($cursor);

You need to set the property that you are passing into your constructor as a property of the class (the variables within methods are scoped in the same way as Java).
You do this using $this->property
// File_Reader
public function __construct(&$file_text)
{
$this->text = $file_text;
}
// Times_File_Reader
public function Scan_File()
{
$errors = array();
$times = array();
$current_time;
$cursor = 0;
$line = 0;
while ($cursor < strlen($this->text))
{
$this->Skip_Whitespace($cursor);
//....lots more code here...
return $times;
}
}
Edit - as an aside you seem to be using some wacky underscorecase/Titlecase hybrid. Best practice in PHP is to use lowerCamelCase for methods and CamelCase for class names.
class FileReader
class TimesFileReader
public function scanFile()
Also - you are passing your variables by reference (&$var) - you probably don't have to do this (the only valid use case I can think of for this is in certain situations using closures/anonymous functions). I'll admit the docs on this are not very clear. http://schlueters.de/blog/archives/125-Do-not-use-PHP-references.html
public function __construct($file_text)
{
$this->text = $file_text;
}

Related

PHP Calling a callback function from within Object method

I am building a scheduler that will take a callback function and will execute that function a given amount of times, and in between a given amount of delay. Below is that the interface for what the functionality looks like.
Side note I am using the Laravel Framework;
public function testBasicTest()
{
$count = 0;
$schedule = new NodeScheduler();
$schedule->retries(2)->delay(100000)->do(function() use ($count) {
$count++;
});
$this->assertEquals($count === 1);
}
This is my test for this piece of functionality and as you can see i want count to equal 2 by the end of it.
My class looks like this;
class NodeScheduler
{
protected $retries = 1;
protected $milliseconds = 10000;
public function __construct()
{
return $this;
}
public function retries($numberOfRetries)
{
$this->retries = $numberOfRetries;
return $this;
}
public function delay($milliSeconds)
{
$this->milliSeconds = $milliSeconds;
return $this;
}
public function do($callback)
{
for($i = 0; $i < $this->retries; $i++){
$callback(); // <<<<<< How Do I Inject The $count Variable Here?
usleep($this->milliseconds);
}
return;
}
}
My test fails with:
Failed asserting that 2 matches expected 0.
Strangely I don't get $count is undefined.
I think i am close, any help greatly appreciated
When you use() a variable from the outer scope inside a function, this creates a copy of the variable into the function's inner scope (an exception is if you're use()ing an object).
If you want to import a variable from the outer scope and modify it, you'll need to pass it in by reference:
$schedule->retries(2)->delay(100000)->do(function() use (&$count) {
$count++;
});
Edit: Also, what #Arno and #Oniyo pointed out: either use assertEquals(1, $count) or use assertTrue($count === 1)
I think you are doing two things wrong
Firstly: As #Arno pointed out,
$this->assertEquals($expected, $actual);
Secondly: From what I see in your code, the loop will run $this->retries's iterations. So, $this->assertEquals($expected, $actual) should be
$this->assertEquals(2, count);
Good luck man!

How do i get my class to use an array from outside the class?

I'm currently trying to get back into object oriented programming How do i get my array inside my class? Global doesn't seam to cut it.
<?
$systems = file_get_contents('https://api.eveonline.com/map/Sovereignty.xml.aspx');
$systems = explode("<row ",$systems);
//print_r($systems);
for ($i = 1; $i <= count($systems); $i++) {
//system name
$systemnames=explode("solarSystemName=",$systems[$i]);
$systemnames=explode('"',$systemnames[1]);
$systemnames=$systemnames[1];
//system id
$systemid=explode("solarSystemID=",$systems[$i]);
$systemid=explode('"',$systemid[1]);
$systemid=$systemid[1];
$systembyid[$systemid]=$systemnames;
$systembyname[$systemnames]=$systemid;
}
class Systems{
public function __construct()
{
global $systembyid;
global $systembyname;
}
function getSystems($system)
{
if (is_numeric($system) && $systembyid[$system]) {
return $systembyid[$system];
}
elseif($systembyname[$system]){
return $systembyname[$system];
}
else{
return "Error: Invalid system id or name";
}
}
}
?>
Try passing the values into the constructor like this, also if you use the & you are just passing a reference and not making a copy of the whole array.
class Systems{
private $sysyembyid;
private $systembyname;
public function __construct(&$systembyid, &$systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
function getSystems($system){
if(is_numeric($system) && $this->systembyid[$system]){
return $this->systembyid[$system];
}
elseif($this->systembyname[$system]){
return $this->systembyname[$system];
}
else{
return "Error: Invalid system id or name";
}
}
}
I prefer to use Dependency Injection. Dependency Injection is when you inject your object's dependencies via the constructor. This ensures that the object will have its dependencies at creation.
class Systems {
protected $systembyid;
protected $systembyname;
public function __construct($systembyid, $systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
public function getSystems($system) {
//Access them with $this-> like below
$this->systembyid[$system];
$this->systembyname[$system];
}
}
Note If you want to be able to modify $systembyid and $systembyname outside of the class, and see the changes within the class, you can pass references to __construct() instead, by specifying the parameters as references:
public function __construct(&$systembyid, &$systembyname)
{
$this->systembyid = $systembyid;
$this->systembyname = $systembyname;
}
Alternatively, you can pass them as parameters to your getSystems() method.
class Systems() {
public function getSystems($system, $systembyid, $systembyname) {
//Do stuff
}
}
The main drawbacks with this approach is that you always have to pass them as parameters to the method, and the method signature could get quite long.
You either need to use the global key word with var in the function where you use it, in this case getSystems() (bad) or pass them into the constructor or the function where you use them, or set them:
Probably the most common case:
public function __construct($s1, $s2)
{
$this->systembyid = $s1
$this->systembyname = $s2
}
//then use $this->systembyid etc in other functions
Or better yet, why not put all that processing code in a function off the class like processSystems() and set the vars there:
public function processSystems($file) {
$systems = file_get_contents($file);
$systems = explode("<row ",$systems);
//print_r($systems);
for ($i = 1; $i <= count($systems); $i++) {
//system name
$systemnames=explode("solarSystemName=",$systems[$i]);
$systemnames=explode('"',$systemnames[1]);
$systemnames=$systemnames[1];
//system id
$systemid=explode("solarSystemID=",$systems[$i]);
$systemid=explode('"',$systemid[1]);
$systemid=$systemid[1];
$systembyid[$systemid]=$systemnames;
$systembyname[$systemnames]=$systemid;
}
$this->systembyid = $systemnames;
$this->systembyname = $systemid;
}
Aside from that, I would say look into simple_xml or DOM for the XML parsing.
Also, you are storing the exact same data in each array. Just use one and either lookup the key or the value.

PHP class recursion: can I create an object of given class inside a method of own class?

Here's what I'd like to do :
class number {
var $value ;
function number($n=0) {
$this->value = $n ;
}
function add($n) {
$x = new number($n) ;
$this->value += $x->value ;
}
}
This example is of course ridiculous, but it illustrates the kind of recursion I'd like to do in a more serious project. (I'll be in fact manipulating images instead of numbers, but I don't suppose it matters here.)
So, should it work ?
Thanks
class Number {
protected $value;
public function __construct($n = 0) {
$this->value = $n;
}
public function add($n) {
$x = new static($n); // or self($x), if you're on PHP < 5.3
$this->value += $x->value;
}
}
Fixed it to actually make it work. Yes, this is entirely possible and sensible (well, it's debatable whether this particular code makes sense, but in general). This is not really recursion. You're just instantiating a class inside a method of another class. It doesn't matter in the slightest that the class you're instantiating is the same as the class that the method you're instantiating it in belongs to (now that's a complicated sentence).
Made example for you. Here is small example:
class number {
var $value ;
function number($n=0) {
$this->value = $n ;
}
function add($n) {
$x = new number($n) ;
$this->value += $x->value ;
return $this->value;
}
}
$foo = new number;
echo $foo->add(2);
echo $foo->add(2);
There was error in your code "$x->value()". Value is not method - it field and should call $x->value

PHP trying to create dynamic variables in classes

I need to construct a class with alot of variables directly from the Database, For simplicity we'll name them 'userX', I've looked into ORM just a little, but its way over my head.
Essentially I thought I could use my procedural code
for ($i=0; $i<100; $i++) {
public ${'user'.$i};
}
But, in a class
class test() {
private $var1;
for ($i=0; $i<10000; $i++) {
public ${'user'.$i};
}
function __constructor .....
}
Obviously not.. but it leaves me with the same problem, how can I add $user0, $user1, $user2, etc etc, without having to type all 10k of them in..
Obviously, it would be 1000x easier to just grab the names from the Database, but again, that looks even harder to code. Should I buckle down and grab them all ORM style?
You could simply use the magic accessors to have as many instance attributes as you wish :
class test{
private $data;
public function __get($varName){
if (!array_key_exists($varName,$this->data)){
//this attribute is not defined!
throw new Exception('.....');
}
else return $this->data[$varName];
}
public function __set($varName,$value){
$this->data[$varName] = $value;
}
}
Then you could use your instance like this :
$t = new test();
$t->var1 = 'value';
$t->foo = 1;
$t->bar = 555;
//this should throw an exception as "someVarname" is not defined
$t->someVarname;
And to add a lot of attributes :
for ($i=0;$i<100;$i++) $t->{'var'.$i} = 'somevalue';
You could also initialize a newly created instance with a given set of attributes
//$values is an associative array
public function __construct($values){
$this->data = $values;
}
Try $this->{$varname}
class test
{
function __construct(){
for($i=0;$i<100;$i++)
{
$varname='var'.$i;
$this->{$varname}=$i;
}
}
}
You can use variable variables ($$var) - content of one variable is used as a name for other variable (double $$)
Therefore not $this->varname but $this->$varname.
class test
{
for($i=0;$i<100;$i++)
{
$varname='var'.$i;
$this->$varname=$i;
}
}
This will dynamically create 100 variables with names $var0, $var1 ...

Combine static var with parent's

This is what I'd like to be able to do:
class Test {
public static $test = 'boo';
}
class Two extends Test {
public static $test = parent::$test.'hoo';
}
// Two::$test == 'boohoo'
Well, specifically combining 2 arrays, but this illustrates it.
Is it possible?
This isn't possible because you can't evaluate anything when declaring a variable.
Something like:
class A {
$seconds_in_a_day = 60*60*24; // invalid
$seconds_in_a_day2 = 86400; // sour but valid
}
is invalid even.
You can move it to the constructor.
public function __construct() {
self::$test = parent::$test.'hoo';
}
Aside from all that .. just don't do it. Save your future self a lot of work and find another more intuitive solution :P

Categories