Initializing array returns null in PHP - php

I'm doing a project using HTML5 WebSockets, with a PHP server using a websockets library right here at Github.
My project also depends on knowing how many players are online. The library has three abstract methods, connected, closed, and process. In connected and closed, it takes a parameter $user, which is a custom class that has a random alphanumeric string as the variable id.
I have a protected $users = []; at the beginning of my class, inside my class, which extends the WebSocketServer that the library provides. In my connected method, I array_push the $user provided to the $users array. Then, in my closed method, I loop through the $users array, checking if the element in $users has the same $id as the $user provided, and then array_splicing that element away if that is try.
So. Here's my problem. When I run my PvPASCIIServer.php as root, and connect using a test web page, everything works fine. BUT, when I disconnect, it says:
PHP Warning: array_splice() expects parameter 1 to be array, null given in /var/www/PvPASCII/PvPASCIIServer.php on line 24
Shouldn't array() not initialize $users as null? Why would it? I've also tried using the literal format of initializing arrays, [], but even that didn't work. And even wierder, my array_push at the beginning of my connected function did not return an error message. Logically, it should have worked and pushed a $user to the end of the $users array, so even if it was initialized null, it should have not been null after that.
My code, if you need it:
#!/usr/local/bin/php
<?
require_once("websockets.php");
class PvPASCIIServer extends WebSocketServer
{
protected $users = [];
protected function connected($user)
{
$this->send($user, "say Pong!");
array_push($this->users, $user);
echo $user->id;
return true;
}
protected function closed($user)
{
echo "Client " + $user->id + " disconnected from the server.";
for($i = 0; $i < sizeof($this->users); $i++)
{
if($this->users[$i]->id == $user->id)
{
array_splice($users, $i, 1); // <-- Line with the error
}
}
}
protected function process($user, $message)
{
// Yet to be determined.
}
}
$host = "localhost";
$port = 3000;
$server = new PvPASCIIServer($host, $port);
$server->run();
?>

$users needs to be $this->users just like everywhere else in your class:
if($this->users[$i]->id == $user->id)
{
array_splice($this->users, $i, 1); // <-- Line with the error
}

array_splice($users, $i, 1); // <-- Line with the error
Should be:
array_splice($this->users, $i, 1); // <-- Line with the error
Since you want to use the class variable $users and not the function variable $users
EDIT:
What John Conde also says (he was a little faster with typing ;-) )

Related

PHP how to send array variables to Class function

I'm writing a code in PHP OOP and I'm trying to send $_POST data
filtered by one Class function to another Class function that will add
the data to database. Specifically login and password in registration
form.
I have 3 Classes that will do that:
Is simple Class that handles connection to database (I think it is not necessary to put code here)
Is the Class that filters the coming $_POST-s:
class Filter extends Dbconnect {
protected $login;
protected $haslo;
public function regFilter() {
if (isset($_POST))
{
foreach($_POST as $key => $val)
{
$filterVal = strip_tags($val);
$filterVal = htmlspecialchars($filterVal);
$filterVal = stripslashes($filterVal);
$filterVal = str_replace("\\", "", $filterVal);
$filter = array(
$key => $filterVal
);
foreach($filter as $key => $val)
{
echo "[$$key]";
echo "$val";
$
{
$key
} = $val;
}
}
return $filter = array(
'login' => $login,
'haslo' => $haslo
);
}
else
{
echo "Proszę podać login i hasło!";
}
}
}
Class that will get login and password and send it to DB:
class Dbinsert extends regFilter{
//protected $login;
//protected $haslo;
protected $query;
protected $dbo;
public function insert(){
//$this->extract = extract($filter);
//$this->login = $login;
//$this->haslo = $haslo;
$this->connect();
$this->query = "INSERT INTO uzytkownik (id, nazwa, haslo) VALUES ('', :login, OLD_PASSWORD(:haslo))";
if(!$result = $this->connect()->prepare($this->query)){
echo 'Zapytanie nie powiodło się';
}
else{
$result->bindParam(':login', $login);
$result->bindParam(':haslo', $haslo);
$login = $_POST['login'];
$haslo = $_POST['haslo'];
$result->execute();
}
$dbo = null;
}
}
Now when I try to send data from form with objects:
$rejestruj = new Dbinsert();
$filtruj = $rejestruj->regFilter();
var_dump($filtruj);
$dodaj = $filtruj->insert();
I get the following result:
[$login]login
[$haslo]password123
array(2) { ["login"]= string(5) "login" ["haslo"]= string(11) "password123" }
Fatal error: Call to a member function insert() on array in `E:\Xampp\htdocs\php\bazy_danych\obiektowe\my\register.php` on line 78
Which doesn't surprises me since: login and haslo is returned from
"foreach" loop in class Filter (which is just for testing) "array(2)"
is returned from "var_dump($filtruj);"(to check if it is actually
working) and error is returned since I send an array to Class
Dbinsert - but in the function I put "extract" to get the variables.
How can I send just the variables from this filtered array to class
Dbinsert?
Edit: As #Twinfriends suggested I corrected function insert in class Dbinsert to actually use prepared statement, thats why (for now) login and haslo variables are reffering to $_POST. Now I need answer to my question.
(First time posting, thanks for edit suggestions, also any advice is appreciated since I'm quite the beginner
in PHP)
Sorry that it took so long to answer, I totally forgot your question. Well, lets take a look at your problem, hope to solve it.
I try to explain it as good as I can, so that you understand whats going on. First of all, lets look at your error message
Fatal error: Call to a member function insert() on array in
E:\Xampp\htdocs\php\bazy_danych\obiektowe\my\register.php on line 78
Okay. Call to a function on array... lets have a look at how you actually call the function:
$rejestruj = new Dbinsert();
$filtruj = $rejestruj->regFilter();
var_dump($filtruj);
$dodaj = $filtruj->insert();
And exactly here is your error. You have to understand that you call methods on objects and pass your data to this methods, not to call the methods on your data. What do I mean with that?
$rejestruj is your Dbinsert object. You create it in your first line of code here. Then, you call the regFilter function on it. Still anything is fine. As you see, var_dump gives you the expected results. So the error has to be on your last lane of code. And indeed, you try to call the method insert() on your array. And that won't work, since your array don't know any method called insert().
The right call to the method would be (Not the final one!!!):
$dodaj = $rejestruj->insert();
Now the method call should work. But in fact, it won't insert anything. Why? Because your insert() method try to bind the variables $login and $haslo - two variables the method don't know. So we need to pass the data in your method. To do that, you have to do the following changes:
Method call:
$rejestruj->insert($filtruj); // $filtruj contains your array
And your Dbinsert should look like:
class Dbinsert extends Dbconnect{
protected $query;
protected $dbo;
public function insert($data){
$this->connect();
$this->query = "INSERT INTO uzytkownik (id, nazwa, haslo) VALUES ('', :login, OLD_PASSWORD(:haslo))";
if(!$result = $this->connect()->prepare($this->query)){
echo 'Zapytanie nie powiodło się';
}
else {
$result->bindParam(':login', $data["login"]);
$result->bindParam(':haslo', $data["haslo"]);
$result->execute();
}
$dbo = null;
}
}
I hope your code works with this changes. So, while in my opinion the code should work now, I want to mention that there are many things you could improve. For example, you're not programming real "object-oriented" ... its more some pseudo OOP you're writing here. Some things are quite bad practice (could be done much easier). I don't want to dive to deep into details, since I don't know if you're interested in it. If you wish I can give you some more advises, but only if you wish.
Otherwise I really hope my answer help you. If the whole thing still doesn't work, please let me know so I can look at it again.
Have a nice day ;)
Edit:
Since it seems I haven't been clear enough, here the code how it should look like now:
$rejestruj = new Dbinsert();
$filtruj = $rejestruj->regFilter();
$dodaj = $rejestruj->insert($filtruj);

Set a referenced variable to a newly initialized class

I have a method, which takes a reference
// CarService.php
public function getCars(&$carCollection = null)
{
$promise = // guzzle request for getting all cars would be here
$promise->then(function (ResponseInterface $response) use (&$carCollection) {
$cars= json_decode($response->getBody(), true);
$carCollection= new CarCollection($cars);
});
}
However, when accessing the collection and trying to reuse it, I'm getting the error
Argument 1 passed to {placeholder} must be an instance of {placeholder}, null given
I know that the reason for this is, that the constructor returns nothing, but how can I still assign my variable to a new instance of the CarCollection (which extends Doctrine's ArrayCollection)
I even tried it with a static method as a work around
// CarCollection.php
public static function create(array $cars): CarCollection
{
$carCollection = new CarCollection($cars);
return $carCollection;
}
// CarService.php
public function getCars(&$carCollection = null)
{
$cars = // curl request for getting all cars would be here
$carCollection = CarCollection::create($cars)
}
but it's still null. Why is that? How can I set a referenced variable to a new class?
I access the method like this
$carService = $this->get('tzfrs.vehicle.services.car');
$carCollection = null;
$promises = [
$carService->getCars($carCollection)
];
\GuzzleHttp\Promise\unwrap($promises);
var_dump($carCollection); // null
When I set the reference directly, eg.
// CarService.php
public function getCars(&$carCollection = null)
{
$carCollection = new CarCollection([]);
}
it works without any problems. Seems like the callback is somehow the problem.
Whoever downvoted this, can you please elaborate why and why you voted to close?
I might be misunderstanding the question, but you should be able to modify an object when passing by reference. See here for an example: https://3v4l.org/KtFvZ
In the later example code that you added, you shouldn't pass $carCollection by reference, the & should only be in the method/function defintion, not provided when you call it. I don't think that is your problem though, that should be throwing an error in php7.

Anybody knows how ->dump() works?

Anybody knows how $myModelClass->dump() works?
I tried several times with models in different states but switched to
var_dump($myModelClass->toArray());
because ->dump() doesn't output (or return) anything for me.
Edit:
And var_dump($myModelClass->dump()); dumps always an empty array.
Edit2:
Here' an example how I use it in the indexAction of IndexController:
public function indexAction() {
$this->view->disable();
$u = new User();
$u = $u::findFirstByUsersId(56);
var_dump($u->dump()); //empty array
$u = new User();
$u = $u->find('usersId = '.(56))->getFirst();
var_dump($u->dump()); //empty array
var_dump($u->toArray()); //correct output
}
Hierarchy for User is:
User <- BaseUser <- UsersStorage <- Phalcon\Mvc\Model
Which should not matter, because the above example gives same results with UsersStorage objects.
Per the PhalconPHP API, ->dump() must be used in conjunction with var_dump().
$myModelClass = SomeClass::find();
foreach ($myModelClass as $record) {
var_dump($record->dump());
exit;
}
or
$myModelClass = SomeClass::findFirst(1);
var_dump($myModelClass->dump());
exit;
http://docs.phalconphp.com/en/latest/api/Phalcon_Mvc_Model.html

I can't get PHPUnit work on my code, it kept saying undefined index: ecs

I am working on a website using someone else's source code called ecshop, a e-commerce website. I want to use PHPUnit to unit test my code but meet a problem.
This is what the error looks like:
C:\Users\maoqiuzi\Documents\Shanglian\XinTianDi\xintiandi\admin>phpunit
--stderr wang_test.php PHPUnit 3.7.27 by Sebastian Bergmann.
E
Time: 1.03 seconds, Memory: 6.75Mb
There was 1 error:
1) ShopTest::test_get_shop_name Undefined index: ecs
C:\Users\maoqiuzi\Documents\Shanglian\XinTianDi\xintiandi\includes\lib_common.ph
p:564
C:\Users\maoqiuzi\Documents\Shanglian\XinTianDi\xintiandi\admin\includes\init.ph
p:147
C:\Users\maoqiuzi\Documents\Shanglian\XinTianDi\xintiandi\admin\wang.php:10
C:\Users\maoqiuzi\Documents\Shanglian\XinTianDi\xintiandi\admin\wang_test.php:10
FAILURES! Tests: 1, Assertions: 0, Errors: 1.
The source code of wang_test.php:
<?php
require_once("wang.php");
class ShopTest extends PHPUnit_Framework_TestCase
{
public function test_get_shop_name()
{
$shop = new Wang();
$first_row_of_shop_list = $shop->get_shop_list();
}
}
The source code of wang.php:
<?php
class Wang
{
private $exchange;
function get_shop_list()
{
define("IN_ECS", 1);
require(dirname(__FILE__).'/includes/init.php');
$this->exchange = new exchange($GLOBALS['ecs']->table('shop'), $GLOBALS['db'], 'shop_id', 'shop_name');
$sql = "SELECT * FROM " . $GLOBALS['ecs']->table('shop');
$shop_list = $GLOBALS['db']->getAll($sql);
if($shop_list != array())
return $shop_list;
else
return array();
}
}
code in init.php
require(ROOT_PATH . 'includes/lib_common.php');
class ECS //line 82
{
var $db_name = '';
var $prefix = 'ecs_';
function ECS($db_name, $prefix)
{
$this->db_name = $db_name;
$this->prefix = $prefix;
}
...
}
...
$ecs = new ECS($db_name, $prefix); // line 114
... // other initialization codes here
$_CFG = load_config(); //line 147
code in lib_common.php
function load_config()
{
$arr = array();
$data = read_static_cache('shop_config');
if ($data === false)
{
$sql = 'SELECT code, value FROM ' . $GLOBALS['ecs']->table('shop_config') . ' WHERE parent_id > 0';
$res = $GLOBALS['db']->getAll($sql);
...
}
I've been working on this for days, and felt very frustrated. Hope anyone help me out! Thanks!!!
As you can see in PHPunit's manual part related on "How to test for PHP errors", how error_reporting is configured affects the test suite; which is your case.
You have (at least) three different options:
Fix the code to check and not use undefined indexes of arrays
Change the error_reporting to ignore notices (one of the examples in the link)
Create (and use) a phpunit.xml configuration file and set convertNoticesToExceptions to false
In init.php, if you change:
$ecs = new ECS($db_name, $prefix);
to:
$GLOBALS['ecs'] = new ECS($db_name, $prefix);
does it start to work (or at least move on to a different error message)?
What I'm thinking is that init.php is expecting it is running as global code, so isn't being explicit like that, but then PHPUnit is doing something clever such that it is not run as global code. So $ecs just ends up being treated as a local variable, not as a global.
(If it does change the error message, go through all other global code in your libraries and change them to use $GLOBALS[...] explicitly too. This is a GoodThing™ to do anyway, as it makes code clearer when other people look at it, and avoids easy-to-make mistakes when refactoring global code into functions.)

Accessing array in class structure

I want to validate a form with php.
Therefor I created a class "benutzer" and a public function "benutzerEintragen" of this class to validate the form:
class benutzer
{
private $username = "";
private $mail = "";
private $mail_check = "";
private $passwort = "";
private $passwort_check = "";
public $error_blank = array();
public $error_notSelected = array();
public $error_notEqual = array();
public function benutzerEintragen () {
$textfields[0] = $this->username;
$textfields[1] = $this->mail;
$textfields[2] = $this->mail_check;
$textfields[3] = $this->passwort;
$textfields[4] = $this->passwort_check;
foreach ($textfields as $string) {
$result = checkFormular::emptyVariable($string);
$error_blank[] = $result;
}
In the function "benutzerEintragen" i filled the variables "username,mail" and so on with the appropriate $_POST entries (not shown in the code above). The call
checkFormular::emptyVariable($string)
just returns "TRUE" if the field is not set or empty otherwise FALSE.
Now when i try to create a new instance of this class, execute the function and get access to $error_blank[0] the array is empty!
if (($_SERVER['REQUEST_METHOD'] == 'POST')){
$BENUTZER = new benutzer();
$BENUTZER->benutzerEintragen();
echo $BENUTZER->error_blank[0];}
So the last line is leading to a "Notice: Undefined offset: 0". It seems to be related to the array structure, because if i do
echo $BENUTZER->mail;
I get any input I wrote in the form, which is correct. Also the foreach loop seems to do the right thing when i run the debugger in phpEd, but it seems like the array "error_blank" is erased after the function is executed.
Any help would be greatly appreciated. Thanks in advance.
There is a scope problem here. You do have a class attribute with the name. Unlike in Java where using a local variable with the same name as a class variable automatically selects the class attribute this is not the case in PHP.
Basically you are saving your output in a local variable which gets discarded once you leave the function. Change $error_blank[] = $result; to $this->error_blank[] = $result; and you should be fine.
First of all this seems overly complicated way to do a simple task, but that wasn't actually the question.
You are creating a new $error_blank variable that is only in function scope. If you wish to use the class variable you should use $this->error_blank[]

Categories