what does the symbol : mean in php? - php

I used print_r on some variables of a framework to figure out their contents and what i saw was like this
Array (
[pages:navigation] => Navigation
[pages:via] => via pages
[item:object:page_top] => Top-level pages
)
I thought this was ok because i can create arrays like
$ar=array('pages:navigation' => 'Navigation',
'pages:via' => 'via pages');
and it would be no problem but when i create this
class student {
public $name;
public function get_name() {
return $name;
}
private $id;
public function get_id() {
return $id;
}
protected $email;
}
$s = new student();
$s->name="hi";
print_r($s);
I get this:
student Object ( [name] => hi [id:student:private] => [email:protected] => )
here the symbol : is automatically inserted for id indicating that it is a member of student and is private but it is not inserted for public member name
I cant figure out what does the symbol : actually mean? Is it some kind of namespacing?

In the array, it has no special meaning. It's just part of the string key; an array key can be any string or integer.
In the object, it's just how print_r displays property names for private properties.
In id:student:private, id is the property name, student the class in which the property is declared, and private is the visibility of the property.

Chances are it's what the script/page is using to separate values in the key of the array. They may use spaces in key names so using a space wasn't acceptable and needed a character that wouldn't normally be found in the value itself.
Much like namespaces in many other languages use the . as a delimiter, that script decided to use : (which is then parsed at a later date most likely and used as its originally intended).
Without seeing the script in it's entirety, this would only be a guess as to implementation.

Related

How to implement PDO FETCH_CLASS in correct way?

Hi world genius of programming. I am quite newbie in PDO and OOP, Please understand.
I try to do the most simple thing in the world - get data from a table in MySQL.
I want to:
1) SELECT * from ... it's about 20 fields.
2) To get an array of object with 4-6 of properties.
3) I want to use fetchAll and FETCH_CLASS...
PDOStatement PDO::query ( string $statement , int $PDO::FETCH_CLASS , string $classname , array $ctorargs )
I've found that we can pass an array of argument but can't implement it.
So what am I doing?
class handler{
connection etc..
public $params = array('surname','id','country','display' );
return $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'person',$this->params);
class person {
public $surname=null;
public $id=null;
public $country=null;
public $status=null;
and then
__construct ()
i will not put it - cause i ve got 50 variants of them(((
}
So, I need to filter options from 20 fields fetching a class but not in SELECT mode instead of *...
Is it possible?
I know that you are genius!
Forgive for newbieness
UPDATE
function __construct($surname,$id,$country,$display) {
$this->surname=$surname;
$this->country=$country;
$id->id->$id
// that the only i need in this oblject
}
function __construct() {
$arg=array('surname','id');
foreach ($arg as $val) {
$this->{$val}=$$val;
}
}
it seems it maybe the next.. not construct function that will filter properties...
UPDATE
I tried solutions as #GolezTrol kindly proposed.
Solution 1 is arguing for... Notice: Undefined property: Person::$_attributes in
if i make
class Entity {
public $_attributes;
function __construct() { ....
or
class Person extends Entity {
public $_attributes;
}
it works.. but i get an object...
[0] => Person Object
(
[_attributes] => Array
(
[0] => surname
[1] => id
[2] => country
[3] => status
)
[id] => 298
.. it's not good(
I think you mean that you want to load only the properties that you specified instead of all values that were returned from the query. Your attempt is to do that by passing the desired field names to the constructor.
Solution 1: Just specify the array of properties and block the rest
Your way might just work, if you get a little help from the __set magic method. Using func_get_args() you can get all the arguments of a function (the constructor in this case) into an array. This way, you get the array of field names that you passed to fetch_all.
The magic setter only sets the properties if they exist in the array that was given to the constructor, so essentially it filters out all fields you don't want.
Advantage: easy. No specific implementation needed in descendant classes. You could just use Entity as a class for all entities.
Disadvantage: magic setter is called for every property and calls in_array this may be slow. fetch_all is determining which fields to read, while maybe this should be the class's responsibility.
class Entity {
function __construct() {
$this->_attributes = func_get_args();
}
function __set($prop, $value) {
if (in_array($prop, $this->_attributes)) {
$this->$prop = $value;
}
}
}
// If you would need a descendant class to introduce methods, you can..
class Person extends Entity {
}
$stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Person', array('id', 'surname', 'gender'))
Solution 2: block all properties that don't exist
Similar solution, but much cleaner, I think. Implement the magic setter and make it do... nothing. It will be called for properties that don't exist and only for properties that don't exist. So in Person you just declare whatever values you want to read. All other properties will be directed to the empty __set method so they are implicitly ignored.
Advantage: Still easy. Hardly any implementation. You can put the empty method in a base class or just implement it in Person and every other class you have. You just declare the properties in Person. You don't even need to specify the fields you want to read in fetch_all. Also, reading into existing properties is faster.
Disadvantage: if you want to read different sets of information into the same class, this is not possible. The person in my example below always has an id, surname and gender. If you want to read for instance id only, you have to introduce another class. But would you want that?..
class Entity {
function __set($prop, $value) {
// Ignore any property that is not declared in the descendant class.
}
}
class Person extends Entity {
public $id = null;
public $surname = null;
public $gender = null;
}
$stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Person')
Solution 3: Read only the fields you want
This is actually the best solution. Instead of selecting all fields, SELECT *, select only the fields you want to have: SELECT id, surname, gender ... This way, you won't have objects with too many values, but more importantly, you also decrease the load on your database. The database doesn't need to fetch the data, PHP doesn't need to receive it, and if the database server is separate from the webserver, you also save network traffic. So in all regards, I think this is the best option.

how to get if array key is protected?

i have this type of array:-
i want to get array elemtn.
context_course Object
(
[_id:protected] => 15
[_contextlevel:protected] => 50
[_instanceid:protected] => 2
[_path:protected] => /1/3/15 [_depth:protected] => 3
)
the problem is [_id:protected]
i want to there value 15
how can i get if element is protected.
thanks.
If a property is protected, it means the developer of the class doesn't want you to be able to freely directly access or modify its value from the public context.
If you analyze the class definition for this object, you will most likely find a method that will give you access to the value, for example it could be:
$obj->getId();
More info: Property Visibility
This is not an array, it is an object.
You will need to implement a public accessor, also known as a getter to access the object property.
class context_course
{
public function getId()
{
return $this->_id;
}
}

How to get the items inside an array in Object Oriented PHP?

I have the following variable available inside a view:
$recent_posts
It is an array so I performed a foreach loop on it and var dumped the result like so:
<? foreach($recent_posts as $post): ?>
<pre><?= var_dump($post) ?></pre>
<? endforeach ?>
This is the output I received from the vardump:
Array
(
[obj] => models\Tag Object
(
[large_image:protected] =>
[small_image:protected] =>
[_obj_id] => 13493
[_validator] =>
[_values:protected] => Array
(
)
[_dirty_values:protected] => Array
(
)
[_type:protected] =>
[_properties:protected] => Array
(
)
[_is_loaded:protected] =>
[_is_static:protected] =>
)
)
How can I retrieve the values for each post. For example how can I get the large_image for a post? I tried this (without knowing what the heck I'm doing) and not surprisingly it didn't work:
<?= $post->large_image ?>
large_image is protected, you cannot access protected members out side of the class (this context).
You have two options, add a getter function for large_image or make it public.
getter is a function that exposes private or protected member, for example
public function get_large_image(){
return $this->large_image;
}
Since $post->large_image is a protected property, you are not allowed to access it outside of the class (or derived classes). I presume there might be a getter method by which you will be able to retrieve the value though (something like get_large_image() perhaps).
To determine what methods are available on the object, either view the source code of the accompanying class, or use reflection:
$refl = new ReflectionClass( $post );
var_dump( $refl->getMethods() );
If there's no method available to get the value, I would not advise you to alter the class, by making the property public (it's been made protected for a reason I presume), or alter the class at all, if it is not your own.
Rather, I would suggest, if possible, you extend the class and create a getter method for the value:
<?php
class MyTag
extends Tag
{
// I would personally prefer camelCase: getLargeImage
// but this might be more in line with the signature of the original class
public function get_large_image()
{
return $this->large_image;
}
}
Of course, this will get tricky soon, if you don't have the means to control the instantiation of the objects.
$post['obj']->large_image should do it.
That property is protected so you may not have access unless you are in the class.

Extending ArrayObject in PHP properly?

Problem: I am trying to extend PHP's ArrayObject as shown below. Unfortunately I can't get it to work properly when setting multi-dimensional objects and instead an error thrown as I have the strict settings enabled in PHP. (Error: Strict standards: Creating default object from empty value)
Question: How can I modify my class to automatically create non-existing levels for me?
The code:
$config = new Config;
$config->lvl1_0 = true; // Works
$config->lvl1_1->lvl2 = true; // Throws error as "lvl1" isn't set already
class Config extends ArrayObject
{
function __construct() {
parent::__construct(array(), self::ARRAY_AS_PROPS);
}
public function offsetSet($k, $v) {
$v = is_array($v) ? new self($v) : $v;
return parent::offsetSet($k, $v);
}
}
Taking a more oop view of your issue, you can create a class that models the concept of an multi-dimensional object.
The solution im posting doesn't extends from ArrayObject to achieve the goals you mention. As you tagged your question as oop, i think it´s important to reinforce the separation the way you store an object's state from how do you access it.
Hope this will help you achieve what you need!
From what you said, an multi-dimensional object is one that:
handles multiple levels of nested information
it does so by providing reading/writing access to the information via properties
behaves nicely when undefined properties are accessed. This means that, for example, you do the following on an empty instance: $config->database->host = 'localhost' the database and host levels are initialized automatically, and host will return 'localhost' when queried.
ideally, would be initialized from an associative arrays (because you can already parse config files into them)
Proposed Solution
So, how can those features be implemented?
The second one is easy: using PHP's __get and __set methods. Those will get called whenever an read/write is beign done on an inaccessible property (one that's not defined in an object).
The trick will be then not to declare any property and handle propertie's operations through those methods and map the property name being accessed as a key to an associative array used as storage. They'll provide basically an interface for accessing information stored internally.
For the third one, we need a way to create a new nesting level when a undeclared property is read.
The key point here is realizing that the returned value for the property must be an multi-dimensional object so further levels of nesting can be created from it also: whenever we´re asked for a property whose name is not present in the internal array, we´ll associate that name with a new instance of MultiDimensionalObject and return it. The returned object will be able to handle defined or undefined properties too.
When an undeclared property is written, all we have to do is assign it's name with the value provided in the internal array.
The fourth one is easy (see it on __construct implementation). We just have to make sure that we create an MultiDimensionalObject when a property's value is an array.
Finally, the fist one: the way we handle the second and third features allows us to read and write properties (declared and undeclared) in any level of nesting.
You can do things like $config->foo->bar->baz = 'hello' on an empty instance and then query for $config->foo->bar->baz successfully.
Important
Notice that MultiDimensionalObject instead of beign itself an array is it composed with an array, letting you change the way you store the object's state as needed.
Implementation
/* Provides an easy to use interface for reading/writing associative array based information */
/* by exposing properties that represents each key of the array */
class MultiDimensionalObject {
/* Keeps the state of each property */
private $properties;
/* Creates a new MultiDimensionalObject instance initialized with $properties */
public function __construct($properties = array()) {
$this->properties = array();
$this->populate($properties);
}
/* Creates properties for this instance whose names/contents are defined by the keys/values in the $properties associative array */
private function populate($properties) {
foreach($properties as $name => $value) {
$this->create_property($name, $value);
}
}
/* Creates a new property or overrides an existing one using $name as property name and $value as its value */
private function create_property($name, $value) {
$this->properties[$name] = is_array($value) ? $this->create_complex_property($value)
: $this->create_simple_property($value);
}
/* Creates a new complex property. Complex properties are created from arrays and are represented by instances of MultiDimensionalObject */
private function create_complex_property($value = array()){
return new MultiDimensionalObject($value);
}
/* Creates a simple property. Simple properties are the ones that are not arrays: they can be strings, bools, objects, etc. */
private function create_simple_property($value) {
return $value;
}
/* Gets the value of the property named $name */
/* If $name does not exists, it is initilialized with an empty instance of MultiDimensionalObject before returning it */
/* By using this technique, we can initialize nested properties even if the path to them don't exist */
/* I.e.: $config->foo
- property doesn't exists, it is initialized to an instance of MultiDimensionalObject and returned
$config->foo->bar = "hello";
- as explained before, doesn't exists, it is initialized to an instance of MultiDimensionalObject and returned.
- when set to "hello"; bar becomes a string (it is no longer an MultiDimensionalObject instance) */
public function __get($name) {
$this->create_property_if_not_exists($name);
return $this->properties[$name];
}
private function create_property_if_not_exists($name) {
if (array_key_exists($name, $this->properties)) return;
$this->create_property($name, array());
}
public function __set($name, $value) {
$this->create_property($name, $value);
}
}
Demo
Code:
var_dump(new MultiDimensionalObject());
Result:
object(MultiDimensionalObject)[1]
private 'properties' =>
array
empty
Code:
$data = array( 'database' => array ( 'host' => 'localhost' ) );
$config = new MultiDimensionalObject($data);
var_dump($config->database);
Result:
object(MultiDimensionalObject)[2]
private 'properties' =>
array
'host' => string 'localhost' (length=9)
Code:
$config->database->credentials->username = "admin";
$config->database->credentials->password = "pass";
var_dump($config->database->credentials);
Result:
object(MultiDimensionalObject)[3]
private 'properties' =>
array
'username' => string 'admin' (length=5)
'password' => string 'pass' (length=4)
Code:
$config->database->credentials->username;
Result:
admin
Implement the offsetGet method. If you are accessing a non exist property, you can create one as you like.
As you are extend ArrayObject, you should use the array way [] to set or get.
Copied pasted your code and it works fine on my PHP test box (running PHP 5.3.6). It does mention the Strict Standards warning, but it still works as expected. Here's the output from print_r:
Config Object
(
[storage:ArrayObject:private] => Array
(
[lvl1_0] => 1
[lvl1_1] => stdClass Object
(
[lvl2] => 1
)
)
)
It is worth noting that on the PHP docs there is a comment with guidance related to what you're trying to do:
sfinktah at php dot spamtrak dot org 17-Apr-2011 07:27
If you plan to derive your own class from ArrayObject, and wish to maintain complete ArrayObject functionality (such as being able to cast to an array), it is necessary to use ArrayObject's own private property "storage".
Detailed explanation is linked above but, in addition to offsetSet which you have and offsetGet which xdazz mentions, you also must implement offsetExists and offsetUnset. This shouldn't have anything to do with your current error but it is something you should be mindful of.
Update: xdazz' second-half has the answer to your problem. If you access your Config object as an array, it works without any errors:
$config = new Config;
$config[ 'lvl1_0' ] = true;
$config[ 'lvl1_1' ][ 'lvl2' ] = true;
Can you do that or are you restricted to the Object syntax for some reason?

Assigning Gettext String to Class Member

I'm making a site that will be translated into x languages.
All strings must be localized.
There are occasions when I need to display a language name, country name or other information that has been retrieved from a database. The data being dealt with in this way will seldom be changed - as above I'm talking about language names, countries etc.
In this example I'm using the array that holds the languages into which the site's UI has been translated. To allow translation of the names (used for title text when the "change language" flag / link is hovered), I have an array like*:
Array("zh_CN" => _("Chinese - Simplified"), "en_GB" => _("English"));
I use them to get the relevant name string for a given language.
Currently I'm using a global array:
$global_langNames = Array("zh_CN" => _("Chinese - Simplified"), "en_GB" => _("English"));
Usage:
global $global_langNames;
echo $global_langNames[$code]; // $code = 'zh_CN'
Output (locale = en_GB):
Chinese Simplified
Output (locale = zh_CN):
简体中文
I would much rather declare this (and other) constant arrays as private members of the class, but it seems PHP isn't willing:
class constants_lang{
private static $langNames = Array("zh_CN" => _("Chinese - Simplified"), "en_GB" => _("English"));
static function getLangName($code){
return self::$langNames($code);
}
}
Results in:
Parse error: syntax error, unexpected '(', expecting ')' in /site/http/includes/classes/constants/lang.php on line 20
Should I hang my head low and go back to the global array, or is there another, better way for me to have a 'constant' array to be used in this manner?
*The array keys are from the database table storing language codes and whether we have a UI translation:
code ui translation
zh_CN 1
en_GB 1
zh_TW 0
....
Solution
class constants{
private $langNamesFromCode;
function __construct()
{
$this->langNamesFromCode = $this->initLangNamesFromCode();
}
/* INIT */
private static function initLangNamesFromCode()
{
return Array("zh_CN" => _("Chinese - Simplified"), "en_GB" => _("English"));
}
/* GETTERS */
public static function getLangNameFromCode($code)
{
if(self::isStatic()){
$langNamesFromCode = self::initLangNamesFromCode();
return $langNamesFromCode[$code];
}
else{
return $this->langNamesFromCode[$code];
}
}
/* UTILITY */
private static function isStatic()
{
return !(isset($this) && get_class($this) == __CLASS__);
}
}
Yes, you can only use (most) literals in variable initializations.
The work-around is something like:
class A {
private $var;
public function init() {
$this->var = func();
}
}
A::init();
You cant use functions in member declarations. If you need to do this move it to the constructor or a static function.

Categories