PHP class public parameter as two dimensional array, how? - php

Ok, so I have a class and I would like to be able to get any trackName (two dimensional array) after initializing an object in another php script. This is a part of the class that is relevant:
class fetchData{
public $artistName;
public $trackName;
public function getArtistTracks(){
$i = 0;
if( $tracks = getTracks() ){
foreach ( $tracks['results'] as $track ){
// $artistName is an array of strings (defined as public)
$name[$this->artistName][$i] = $track['name'];
$i++;
}
}
return $name;
}
// later in the class one other function there is this
function initialize(){
...
...
$this->trackName = $this->getArtistTracks();
}
}
Here is how I thought I could call artistName and trackName from another script:
$temp = new fetchData();
echo $temp->artistName[3]; // this works (returns 'some_artist_name' for example)
echo $temp->trackName[$temp->artistName[3]][1]; // this doesn't work
echo $temp->trackName['some_artist_name'][1]; // this also doesn't work
I tried a few other ways. For example instead of this:
$name[$this->artistName][$i] = $track['name'];
I would put this:
$this->name[$this->artistName][$i] = $track['name'];
without the return in getArtistTracks() and without the line in initialize() but that didn't work also. how can I get these trackNames from within another script?
thank you =)

to close this one up, the function should look like this ($i was in the wrong loop):
public function getArtistTracks(){
if( $tracks = getTracks() ){
$i = 0;
foreach ( $tracks['results'] as $track ){
// $artistName is an array of strings (defined as public)
$name[$this->artistName][$i] = $track['name'];
$i++;
}
}
return $name;
}

$name[$this->artistName ---> [$i] <--- ] = $track['name'];
of course, only if $temp->artistName; is array.

Related

Organising an array of URLs by hierarchy

I have built a web scraper that recursively gets all URLs from a specific website and stores them in an array
Example below:
$array = [
'http://site.test',
'http://site.test/blog',
'http://site.test/blog/blog1',
'http://site.test/blog/blog2',
'http://site.test/services',
'http://site.test/services/service1',
'http://site.test/services/service2',
'http://site.test/services/service2/sub-service',
'http://site.test/product',
'http://site.test/product/product1',
'http://site.test/product/product1',
];
I am looking for some sort of way to organise this array into a multidimensional array so that I can see what pages are child pages and of which section something like the below structure
ie:
Home
----blog
--------article1
--------article2
----services
--------service1
--------service2
------------sub-service1
-----product
--------product1
--------product2
I have tried looping through and extracting certain segments of each string but cannot seem to get the desired result.
Ideally I would like to have the result in an array or even in displayed in a multi-level list for display purposes.
Any guidance would be much appreciated!
Let's try) we have an array of links
$array = [
'http://site.test',
'http://site.test/blog',
'http://site.test/blog/blog1',
'http://site.test/blog/blog2',
'http://site.test/services',
'http://site.test/services/service1',
'http://site.test/services/service2',
'http://site.test/services/service2/sub-service',
'http://site.test/product',
'http://site.test/product/product1',
'http://site.test/product/product2',
];
For creating a tree we should create the Node class
class Node
{
private array $childNodes;
private string $name;
public function __construct(string $name)
{
$this->name = $name;
$this->childNodes = [];
}
public function getName(): string
{
return $this->name;
}
public function addChildNode(Node $node): void
{
$this->childNodes[$node->getName()] = $node;
}
public function hasChildNode(string $name): bool
{
return array_key_exists($name, $this->childNodes);
}
public function getChildNode(string $name): Node
{
return $this->childNodes[$name];
}
public function getChildNodes(): array
{
return $this->childNodes;
}
}
And Tree class, that used Node class.
Method appendUrl parses URL and builds nodes chain.
class Tree
{
private Node $head;
public function __construct()
{
$this->head = new Node('Head');
}
public function getHead(): Node
{
return $this->head;
}
public function appendUrl(string $url): void
{
$parsedUrl = parse_url($url);
$uri = sprintf('%s//%s', $parsedUrl['scheme'], $parsedUrl['host']);
$keys = array_filter(explode('/', $parsedUrl['path'] ?? ''));
$keys = [$uri, ...$keys];
$node = $this->head;
foreach ($keys as $key) {
if (!$node->hasChildNode($key)) {
$prevNode = $node;
$node = new Node($key);
$prevNode->addChildNode($node);
} else {
$node = $node->getChildNode($key);
}
}
}
}
Now we create ConsoleTreeDrawer class that draw our tree to console
class ConsoleTreeDrawer
{
public function draw(Tree $tree): void
{
$node = $tree->getHead();
$this->drawNode($node);
}
private function drawNode(Node $node, int $level = 1): void
{
$prefix = implode('', array_fill(0, 2 * $level, '-'));
print("{$prefix}{$node->getName()}\n");
foreach ($node->getChildNodes() as $childNode) {
$this->drawNode($childNode, $level + 1);
}
}
}
And let`s use our classes
$tree = new Tree();
foreach ($array as $url) {
$tree->appendUrl($url);
}
$drawer = new ConsoleTreeDrawer();
$drawer->draw($tree);
And we drew the tree
--Head
----http//site.test
------blog
--------blog1
--------blog2
------services
--------service1
--------service2
----------sub-service
------product
--------product1
Algorithm:
Remove the prefix http:// for now as it is useless for our requirement. You can add it later on again.
Next is to sort all the elements using usort. Here, based on length obtained from exploding based on /.
Now, we can be assured that all parents are before child in the array.
Next is to assign version number/rank to each link. Naming is as follows:
'http://site.test' => 1
'http://site.test/blog' => 1.1
'http://site.test/services' => 1.2
'http://site.test/blog/blog1' => 1.1.1
Above is the strategy in which version numbers will be assigned.
Now, we just need to sort the array based on this version numbers using uasort
and you are done.
Snippet:
<?php
$array = [
'http://site.test',
'http://site.test/blog',
'http://site.test/blog/blog1',
'http://site.test/blog/blog2',
'http://site.test/services',
'http://site.test/services/service1',
'http://site.test/services/service2',
'http://site.test/services/service2/sub-service',
'http://site.test/product',
'http://site.test/product/product1',
];
// remove http://
foreach($array as &$val){
$val = substr($val,7);
}
// sort based on length on explode done on delimiter '/'
usort($array, function($a,$b){
return count(explode("/",$a)) <=> count(explode("/",$b));
});
$ranks = [];
$child_count = [];
// assign ranks/version numbers
foreach($array as $link){
$parent = getParent($link);
if(!isset($ranks[$parent])){
$ranks[$link] = 1;
}else{
$child_count[$parent]++;
$ranks[$link] = $ranks[$parent] . "." . $child_count[$parent];
}
$child_count[$link] = 0;
}
function getParent($link){
$link = explode("/",$link);
array_pop($link);
return implode("/",$link);
}
// sort based on version numbers
uasort($ranks,function($a,$b){
$version1 = explode(".", $a);
$version2 = explode(".", $b);
foreach($version1 as $index => $v_num){
if(!isset($version2[$index])) return 1;
$aa = intval($v_num);
$bb = intval($version2[$index]);
if($aa < $bb) return -1;
if($bb < $aa) return 1;
}
return count($version1) <=> count($version2);
});
// get the actual product links that were made as keys
$array = array_keys($ranks);
print_r($array);// now you can attach back http:// prefix if you like
Note: Current algorithm removes duplicates as well as there is no point in keeping them.
#Update:
Since you need a multidimensional hierarchical array, we can keep track of parent and child array link references and insert children into their respective parents.
<?php
$array = [
'http://site.test',
'http://site.test/blog',
'http://site.test/blog/blog1',
'http://site.test/blog/blog2',
'http://site.test/services',
'http://site.test/services/service1',
'http://site.test/services/service2',
'http://site.test/services/service2/sub-service',
'http://site.test/product',
'http://site.test/product/product1',
];
foreach($array as &$val){
$val = substr($val,7);
}
usort($array, function($a,$b){
return count(explode("/",$a)) <=> count(explode("/",$b));
});
$hier = [];
$set = [];
foreach($array as $link){
$parent = getParent($link);
if(!isset($set[$parent])){
$hier[$link] = [];
$set[$link] = &$hier[$link];
}else{
$parent_array = &$set[$parent];
$parent_array[$link] = [];
$set[$link] = &$parent_array[$link];
}
}
function getParent($link){
$link = explode("/",$link);
array_pop($link);
return implode("/",$link);
}
print_r($hier);

Combine four foreach into one foreach?

I am trying to add 4 foreach into one. I know how to add 2 foreach into one like this :
foreach (array_combine($images, $covers) as $image => $cover) {
But i want to add more two foreach $titles as $title and $albums as $album.
I am not sure want like this :
foreach (array_combine($images, $covers) as $image => $cover) {
foreach (array_combine($titles, $albums) as $title => $album) {
echo "$image-$cover-$title-$album"
It show me duplicate of every output.I mean output is
demo-demo1-demo2-demo3demo-demo1-demo2-demo3
Need output only
demo-demo1-demo2-demo3
Put the for each statement in a function. Then create a loop that calls it.
public function loopMe($images, $covers)
{
foreach (array_combine($images, $covers) as $image => $cover) {
$this->loopMe($image,$cover);
}
}
It looks like your second for loop is being called multiple times per item in the first for loop. So you want to make sure that you are only calling the second for loop once per image cover. or set an index cap on the second for loop. For instance if you are tyring to map the first item in the first for loop to the first item in the second for loop you should use an index.
public function loopMe($images)
{
for ($i = 0; $i < count($images); $i++) {
echo $images[$i] . '-'. $title[$i] . '-' . $cover[$i] . '-'. $album[$i];
}
}
I think you are approaching this problem from the wrong angle. From what I can tell, you are trying to output the properties of something. I think what you want to do is approach this from an object-oriented approach by creating a class and using a method to output the contents of your object.
Something like this:
class MyAlbumThing {
protected $image;
protected $cover;
protected $title;
protected $album;
public __construct($image, $cover, $title, $album) {
$this->image = $image;
$this->cover = $cover;
$this->title = $title;
$this->album = $album;
}
public getImage() {
return $this->image;
}
public getCover() {
return $this->cover;
}
public getTitle() {
return $this->title;
}
public getAlbum() {
return $this->album;
}
public getString() {
return $this->image . '-' .
$this->cover . '-' .
$this->title . '-' .
$this->album;
}
}
Then, you can instantiate this class and print your properties:
MyAlbumThing album = new MyAlbumThing("demo", "demo1", "demo2", "demo3");
echo $album->getString();
Would output:
demo-demo1-demo2-demo3
Also, if you hav a lot of these things, then you would use a foreach, like so:
$myAlbumArray = new array();
$myAlbumArray[] = new MyAlbumThing("demo", "demo1", "demo2", "demo3");
$myAlbumArray[] = new MyAlbumThing("anotherdemo", "anotherdemo1", "anotherdemo2", "anotherdemo3");
$lengthOfArray = sizeof(myAlbumArray);
for ($i = 0; $i < $lengthOfArray; $i++) {
echo $myAlbumArray[$i]->getString();
}
Sorry for any errors in my syntax, I wrote that in the browser without the help of my IDE.
I highly recommend learning more about object-oriented PHP programming. I found this article especially helpful while I was learning: http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762
EDIT:
Please mark this answer as correct if you did indeed find this helpful for your problem.

Recursive function with unknown depth of values. Return all values (undefined depth)

I have a question about a recursive PHP function.
I have an array of ID’s and a function, returning an array of „child id’s“ for the given id.
public function getChildId($id) {
…
//do some stuff in db
…
return childids;
}
One childid can have childids, too!
Now, I want to have an recursive function, collecting all the childids.
I have an array with ids like this:
$myIds = array("1111“,"2222“,"3333“,“4444“,…);
and a funktion:
function getAll($myIds) {
}
What I want: I want an array, containing all the id’s (including an unknown level of childids) on the same level of my array. As long as the getChildId($id)-function is returning ID’s…
I started with my function like this:
function getAll($myIds) {
$allIds = $myIds;
foreach($myIds as $mId) {
$childids = getChildId($mId);
foreach($childids as $sId) {
array_push($allIds, $sId);
//here is my problem.
//what do I have to do, to make this function rekursive to
//search for all the childids?
}
}
return $allIds;
}
I tried a lot of things, but nothing worked. Can you help me?
Assuming a flat array as in your example, you simply need to call a function that checks each array element to determine if its an array. If it is, the function calls it itself, if not the array element is appended to a result array. Here's an example:
$foo = array(1,2,3,
array(4,5,
array(6,7,
array(8,9,10)
)
),
11,12
);
$bar = array();
recurse($foo,$bar);
function recurse($a,&$bar){
foreach($a as $e){
if(is_array($e)){
recurse($e,$bar);
}else{
$bar[] = $e;
}
}
}
var_dump($bar);
DEMO
I think this code should do the trick
function getAll($myIds) {
$allIds = Array();
foreach($myIds as $mId) {
array_push($allIds, $mId);
$subids = getSubId($mId);
foreach($subids as $sId) {
$nestedIds = getAll($sId);
$allIds = array_merge($allIds, $nestedIds);
}
}
return $allIds;
}

How to fill an array with another array?

I'm trying to create clones of an element in an object and set new names for the clones.
class My_Obj{
var $obj;
var $obj_name;
var clone; //----int input to say how many clones are needed
var clone_names;//----array input to make clone's name different from $obj
function __construct( $args = '' ) {
$defaults=array(
/* codes to set up the default $obj */
)
if ( $this->clone >0 ){
for ( $i = 0; $i <= $this->clone; ++$i ){
$clone_obj[$i]['name'] = /* need to loop through array $clone_name to fill this */
}
}
/* other codes */
}
The $clone_names, for example, can be array('cat', 'dog', 'bird'). It doesn't matter which order as long as each clone get a name. I would like to learn how to do this. Thanks!
If I understand your question correctly, you want to fill the array $clone_obj with values from $clone_names - up to the number of clones specified in $clone?
If that's the case, this may work (I've rewritten the sample class you used):
class My_Obj {
public $clone = 0; //----int input to say how many clones are needed
public $clone_names = array(); //----array input to make clone's name different from $obj
private $clone_obj = array(); // array to store cloned names in
function __construct($args = '') {
for ($i=0; $i<$this->clone; $i++) {
// copy the name in "$clone_names" to "$clone_obj", if it exists
$this->clone_obj[$i] = array();
$this->clone_obj[$i]['name'] = (isset($this->clone_names[$i]) ? $this->clone_names[$i] : '');
}
}
}

How to get a strings data from a different function?

I have a php file with different functions in it. I need to get data from strings in a function, but the strings have been specified in a different function. How can this be done please?
... To clarify, I have two functions.
function a($request) { $username = ...code to get username; }
the username is over retreivable during function a.
function b($request) { }
function b need the username, but cannot retrieve it at the point its called, so need it from function a. I am very much a beginer here (so bear with me please), I tried simply using $username in function b, but that didn't work.
Can you please explain how I can do this more clearly please. There are another 5 strings like this, that function b needs from function a so I will need to do this for all the strings.
...Code:
<?php
class function_passing_variables {
function Settings() {
//function shown just for reference...
$settings = array();
$settings['users_data'] = array( "User Details", "description" );
return $settings;
}
function a( $request ) {
//This is the function that dynamically gets the user's details.
$pparams = array();
if ( !empty( $this->settings['users_details'] ) ) {
$usersdetails = explode( "\n", Tool::RW( $this->settings['users_data'], $request ) );
foreach ( $usersdetails as $chunk ) {
$k = explode( '=', $chunk, 2 );
$kk = trim( $k[0] );
$pparams[$kk] = trim( $k[1] );
}
}
$email=$pparams['data_email'];
$name=$pparams['data_name'];
$username=$pparams['data_username'];
//These variables will retrieve the details
}
function b( $request ) {
//Here is where I need the data from the variables
//$email=$pparams['data_email'];
//$name=$pparams['data_name'];
//$username=$pparams['data_username'];
}
}
?>
#A Smith, let me try to clarify what you mean.
You have several variables, example : $var1, $var2, etc.
You have two function (or more) and need to access that variables.
If that what you mean, so this may will help you :
global $var1,$var2;
function a($params){
global $var1;
$var1 = 1;
}
function b($params){
global $var1,$var2;
if($var1 == 1){
$var2 = 2;
}
}
Just remember to define global whenever you want to access global scope variable accross function. You may READ THIS to make it clear.
EDITED
Now, its clear. Then you can do this :
class function_passing_variables{
// add these lines
var $email = "";
var $name = "";
var $username = "";
// ....
Then in your function a($request) change this :
$email=$pparams['data_email'];
$name=$pparams['data_name'];
$username=$pparams['data_username'];
to :
$this->email=$pparams['data_email'];
$this->name=$pparams['data_name'];
$this->username=$pparams['data_username'];
Now, you can access it in your function b($request) by this :
echo $this->email;
echo $this->name;
echo $this->username;
In the functions where the string has been set:
Global $variable;
$variable = 'string data';
Although you really should be returning the string data to a variable, then passing said variable to the other function.

Categories