Undefined variable answers eventhough variable is defined - php

<?php
class Question_model extends CI_Model {
public $answers;
public function filter_answers($value){
if(is_string($value))
{
if(strpos($value,"option") !== false){
$this->$answers[] = str_replace("option","",$value);
}
}
}
public function create_question($data){
$data = array(
'explanation' => $data['exp'],
'name' => $data['name']
);
$this->db->insert('question', $data);
array_filter($data,array($this,"filter_answers"));
echo $this->$answers;
}
}
I am using codeigniter framework and i am getting this in model as you can see that variable is actually defined and not the other way around. I am calling model from codeigniter controller.

You must be call answer property with $this->answers, not by $this->$answers.
<?php
class Question_model extends CI_Model {
public $answers;
public function filter_answers($value){
if(is_string($value))
{
if(strpos($value,"option") !== false){
$this->answers[] = str_replace("option","",$value);
}
}
}
public function create_question($data){
$data = array(
'explanation' => $data['exp'],
'name' => $data['name']
);
$this->db->insert('question', $data);
array_filter($data,array($this,"filter_answers"));
echo $this->answers;
}
}

The double arrow operator, “=>”, is used as an access mechanism for
arrays. This means that what is on the left side of it will have a
corresponding value of what is on the right side of it in array
context. This can be used to set values of any acceptable type into a
corresponding index of an array. The index can be associative (string
based) or numeric.
<?php
$myArray = array(
0 => 'Big',
1 => 'Small',
2 => 'Up',
3 => 'Down'
);
?>
The object operator, “->”, is used in object scope to access methods
and properties of an object. It’s meaning is to say that what is on
the right of the operator is a member of the object instantiated into
the variable on the left side of the operator. Instantiated is the key
term here.
<?php
$obj = new MyObject(); // Create a new instance of MyObject into $obj
$obj->thisProperty = 'Fred'; // Set a property in the $obj object called thisProperty
$obj->getProperty(); // Call a method of the $obj object named getProperty
?>
Example
<?php
class Question_model extends CI_Model {
public $answers;
public function filter_answers($value){
if(is_string($value))
{
if(strpos($value,"option") !== false){
$this->answers[] = str_replace("option","",$value);
}
}
}
public function create_question($data){
$data = array(
'explanation' => $data['exp'],
'name' => $data['name']
);
$this->db->insert('question', $data);
array_filter($data,array($this,"filter_answers"));
echo $this->answers;
}
}

Related

How to iterate over array of objects with private properties in Mustache properly?

Example of mustache template:
{{#entites}}
{{title}}
{{/entities}}
Rendered by:
$m = new Mustache_Engine(
['loader' => new Mustache_Loader_FilesystemLoader('../views')]
);
echo $m->render('index', $data);
Basic nested array.
$data = [
'entities' => [
[
'title' => 'title value',
'url' => 'url value',
]
]
];
This is rendered properly in template.
Array of objects of class:
class Entity
{
private $title;
private $url;
//setter & getters
public function __get($name)
{
return $this->$name;
}
}
Mustache argument:
$data = [
'entities' => [
$instance1
]
];
In this case not working - output is empty (no values from properties)
Instead of magic methods, why don't you use a function like this in the class
public function toArray()
{
$vars = [];
foreach($this as $varName => $varValue) {
$vars[$varName] = $varValue;
}
return $vars;
}
then call that function to grab the variables as array
$data = [
'entities' => $instance1->toArray()
];
You can make a use of ArrayAccess Interface, to be able to access your private properties as follow:
class Foo implements ArrayAccess {
private $x = 'hello';
public $y = 'world';
public function offsetExists ($offset) {}
public function offsetGet ($offset) {
return $this->$offset;
}
public function offsetSet ($offset, $value) {}
public function offsetUnset ($offset) {}
}
$a = new Foo;
print_r($a); // Print: hello
Of course this is a trivial example, you need to add more business logic for the rest of the inherited methods.

Set object properties at constructor call time (PHP)

I wonder if it's possible to achieve similar functionality to C#'s compact instantiation syntax:
itemView.Question = new ItemViewQuestion()
{
AnswersJSON = itemView.Answer.ToJSONString(),
Modified = DateTime.Now,
ModifiedBy = User.Identity.Name
};
I wish to be able to create an object of arbitrary class passing their properties without having to set up constructor code for these properties.
To put up another example, this can be done with stdClass like this:
(object) ["name" => "X", "age" => 30]
Type juggling does not work for custom classes, however.
There is no such functionality natively in PHP, unfortunately.
But you can create a class in your project and extend it in the classes you wish to instantiate without a constructor. Something like this:
<?php
class Fillable{
public static function fill($props)
{
$cls = new static;
foreach($props as $key=>$value){
if (property_exists(static::class,$key)){
$cls->$key = $value;
}
}
return $cls;
}
}
class Vegetable extends Fillable
{
public $edible;
public $color;
}
$veg = Vegetable::fill([
'edible' => true,
'color' => 'green',
'name' => 'potato' //Will not get set as it's not a property of Vegetable. (you could also throw an error/warning here)
]);
var_dump($veg);
Checkout this fiddle for the working example
This is valid in PHP though:
<?php
class Demo {
public function getA() {
return $this->Options['A'];
}
}
$D = new Demo();
$D->Options = Array(
'A' => '1',
'B' => '2',
'C' => '3'
);
var_dump($D->getA());
Or, something like this:
<?php
class Demo {
public function __construct($Options) {
$this->Options = $Options;
}
public function getA() {
return $this->Options['A'];
}
}
$D = new Demo(Array(
'A' => '1',
'B' => '2',
'C' => '3'
));
var_dump($D->getA());
Or even this:
<?php
class Demo {
public function __construct($Options) {
foreach ($Options as $key=>$value) $this->$key = $value;
}
public function getA() {
return $this->A;
}
}
$D = new Demo(Array(
'A' => '1',
'B' => '2',
'C' => '3'
));
var_dump($D->getA());
I guess it really depends what are you trying to achieve? You said you do not want to use magic functions or setters, but is there more to it?
Obviously php doesn't have this. Somewhere a function is required. I did an implementation using a trait which is close.
<?php
Trait Init {
public function init($arr) {
$vars = get_object_vars($this);
foreach($arr as $k => $v) {
if ( array_key_exists($k, $vars) ) $this->$k = $v;
}
}
}
class Demo {
use Init;
public $answersJSON;
public $modified;
public $modifiedBy;
}
$obj = new Demo();
$obj->init(['modified' => 'now']);
print_r($obj);

Slim framework unable to encode to json with protected variables

Basically I was encoding a response with json and couldn't figure out why it kept returning the right number of array members but they were empty.
$app->get('/api/server_list', function ($request, $response, $args) {
$serverlist = new ServerListing($this->db);
$servers = $serverlist->getServers();
$newResponse = $response->withJson($servers);
return $newResponse;
});
This is the output of the above with an added print_r($servers)
[{},{}]Array
(
[0] => ServerEntity Object
(
[id:protected] => 1
[serverName:protected] => dc1.domain.com
)
[1] => ServerEntity Object
(
[id:protected] => 2
[serverName:protected] => dc2.domain.com
)
)
Here is the class code for ServerListing:
<?php
class ServerListing extends Listing
{
public function getServers() {
$sql = "SELECT * from servers";
$stmt = $this->db->query($sql);
$results = [];
while($row = $stmt->fetch()) {
$results[] = new ServerEntity($row);
}
return $results;
}
}
Here is ServerEntity:
<?php
class ServerEntity
{
public $id;
public $serverName;
public function __construct(array $data) {
if(isset($data['id'])) {
$this->id = $data['id'];
}
$this->serverName = $data['name'];
}
public function getId() {
return $this->id;
}
public function getServerName() {
return $this->serverName;
}
}
Only way it works is with public.
I understand public/private/protected. Though this is my first time with a framework and Object Oriented php.
Using the same database call in another route I can then pass the server list to a view and it works fine.
So I guess two questions.
Why does the json encode fail?
Am I doing something fundamentally wrong/ is there a better way to do this?
Slim's Response::withJson() doesn't do anything magic. It relies on the PHP function json_encode() to do the encoding. json_encode() also doesn't know any special trick. If you pass an object to it to encode it gets all the data it can get from it. And that means only its public properties because, well, this is how OOP works.
However, if you implement the JsonSerializable interface in a class then you can control what data is available to json_encode() when it comes to encode an object of that class.
For example:
class ServerEntity implements JsonSerializable
{
private $id;
private $serverName;
// ... your existing code here
public function jsonSerialize()
{
return array(
'id' => $this->id,
'name' => $this->serverName,
);
}
}
Some test code:
echo(json_encode(new ServerEntity(array('id' => 7, 'name' => 'foo'))));
The output is:
{"id":7,"name":"foo"}
In short, an object can be converted into an array.
The object's public properties will be used as $key => $value pairs in the array.
Since the properties are protected, the values are not included.
While it would seem logical that the array actually be empty, the process in which PHP converts the object to an array is not really documented well enough.
In practice what I would recommend is you create a public method that converts the Object to an array.
class ServerEntity {
//...
public function toArray() {
return array("id" => $this->id, "name" => $this->name);
}
//...
}
Then you may simply do...
$app->get('/api/server_list', function ($request, $response, $args) {
$serverlist = new ServerListing($this->db);
$servers = $serverlist->getServers();
$objects = array();
foreach ($servers as $server) {
$objects[] = $server->toArray();
}
$newResponse = $response->withJson($objects);
return $newResponse;
});

Define data members within constructor

I have got this little snippet of code, I want to be able to define each array element as a new data member.
class Core_User
{
protected $data_members = array(
'id' => '%d',
'email' => '"%s"',
'password' => '"%s"',
'title' => '"%s"',
'first_name' => '"%s"',
'last_name' => '"%s"',
'time_added' => '%d' ,
'time_modified' => '%d' ,
);
function __construct($id = 0, $data = NULL)
{
foreach($this->data_members as $member){
//protected new data member
}
}
//protected new data member
You won't be able to create a non-public property at runtime. If protected is paramount, you can declare a protected array or object and insert key/values into it in the constructor
Always use $this when you want to access object's members (it should be $this->data_members in constructor).
You can try defining magic methods __get & __set (I'm not sure if they can be protected though). :
protected function __get($name){
if (array_key_exists($name,$this->data_memebers))
{
return $this->data_memebers[$name];
}
throw new Exception("key $name doesn't not exist");
}
protected function __set($name,$value){
if (array_key_exists($name,$this->data_memebers))
{
$this->data_memebers[$name] = $value;
}
throw new Exception("key $name doesn't not exist");
}
What you want to achieve is possible, however you won't be able to make the new properties protected (as this is only possible for predefined members).
function __construct($id = 0, $data = NULL)
{
foreach($this->$data_memebers as $name => $value ){
$this->$name = $value;
}
}
Note the use of the $ before name in $this->$name: This makes PHP use the current value of the $name variable as property.

Why is my getter magic method using a class instance as an index?

here's my getter:
public function __get($field)
{
if ($field == 'userId'):
return $this->uid;
else:
return $this->fields[$field];
endif;
}
here's my constructor
public function __construct()
{
$this->uid = null;
$this->fields = array(
'username' => '',
'password' => '',
'firstname' => '',
'lastname' => '',
'email' => '',
'is_active' => false
);
$this->session = Session::Instance();
$this->profiler = new Profiler();
$this->encrypt = new Encrypt();
}
everytime i access this function:
private function handle_pass($password, $username=null, $encrypt=true)
{
if ($encrypt) :
return $this->encrypt->encode($password);
else:
$query = ORM::factory('user');
$result = $query
->select('password')
->where('username', $username)
->find();
$compare_pass = $this->encrypt->decode($password);
return ($compare_pass === $result->password);
endif;
}
i get this error
application/libraries/User.php: Undefined index: encrypt // this is the error message
application/libraries/User.php:User->__get( encrypt ) // this is the last method executed
Is encrypt defined as a public variable in the class? If not, the logic of your __get() function demands that it be read from $this->fields['encrypt'], which is never set, and is what's producing that error.
Use get_object_vars on the object before attempting to access the encrypt property to see if it really exists. Something else could be going on.
var_dump(get_object_vars($myClass));
Edit:
After looking at your code. The get() method should never be called since it is only invoked when a referenced property is inaccessible. Are you declaring $encrypt as private? Are you declaring it at all? What makes you think get() should be invoked? (Formatter goes crazy when I try to put underscores infront of get() with a link).
class myClass()
{
public $encrypt;
public function __construct()
{
$this->encrypt = new Encrypt();
}
public function __get($property)
{
return $this->$property;
}
public function handle_pass()
{
$this->encrypt->decode();
// Since $encrypt is public, __get() will not be invoked
}
}

Categories