php数据分组_使用PHP类将内存中的数据分组

php数据分组

目的 (Purpose)

When attempting to explain Object Oriented Programming (OOP) to people it is sometimes hard to explain the concepts in a way that is simple, but not so absurdly that it involves writing example code to manipulate bananas, apples or the colour blue.

当试图向人们解释面向对象编程(OOP)时,有时很难以简单但不荒谬的方式解释概念,以至于涉及编写示例代码来操纵香蕉,苹果或蓝色。

So here is a simple, real world example of how OOP can make your programming life a lot easier. It involves a very common task - collecting data, reorganizing it, selecting parts of it and then using it on a webpage. I will also show how the use of OOP allows simple expandability of the code in a way that makes maintenance easy. This code is based on a real question from the Experts Exchange PHP section and I am grateful to EE member maccaj51 who agreed to let me use the questions as the basis for this article.

因此,这是一个简单而真实的示例,说明OOP如何使您的编程生活变得更加轻松。 它涉及一个非常普通的任务-收集数据,重新组织,选择其中的一部分然后在网页上使用它。 我还将展示OOP的使用如何以易于维护的方式使代码具有简单的可扩展性。 这段代码基于来自Experts Exchange PHP部分的一个真实问题,我感谢EE成员maccaj51,他同意让我将这些问题用作本文的基础。

要解决的问题 (The problem to be solved)

The brief is to accept data from an RSS feed sort it and select some of the data. The program code will then be extended to work with a number of feeds

简要说明是接受来自RSS提要的数据并对其进行排序,然后选择一些数据。 然后,程序代码将扩展为可用于许多提要

Let us begin by looking at the RSS feed in question. The structure of the bit we are interested in looks like this.

让我们首先查看有问题的RSS feed。 我们感兴趣的钻头的结构如下所示。

<item>
<title>Ar&#xEA;ches - Beaufort</title>
<description>Closed  / Past 48 Hours: 0 cm / Primary: Hard Packed / Base Depth: 170 cm</description>
<guid isPermaLink="true">http://www.onthesnow.co.uk/france/areches-beaufort/skireport.html?XE_AFF=rss</guid>
<pubDate>Fri,  4 Jun 2010 04:47:05 -0400</pubDate>
<ots:open_staus>Closed</ots:open_staus>
<ots:resort_id>2658</ots:resort_id>
<ots:base_depth>170</ots:base_depth>
<ots:snowfall_48hr>0</ots:snowfall_48hr>
<ots:region_name>France</ots:region_name>
<ots:surface_condition>Hard Packed</ots:surface_condition>
<ots:base_depth_metric>cm</ots:base_depth_metric>
<ots:snowfall_48hr_metric>cm</ots:snowfall_48hr_metric>
<ots:resort_rss_link>http://www.onthesnow.co.uk/france/areches-beaufort/snow.rss</ots:resort_rss_link>
</item>

and the information we want to collect is

我们要收集的信息是

- The title

- 标题

- The snow depth

-雪深

- The date

- 日期

储存资料 (Storing the data)

Rather than storing this in three arrays and passing them round everywhere, I propose that you should group the data in a simple PHP class which has little or no other purpose than simply grouping the data. I will not be applying the normal rules of data access and making class data "protected" or "private". So, we might start with this:

我建议不要将数据存储在三个数组中并在各处传递,而应该将数据分组到一个简单PHP类中,该类除了简单地对数据进行分组外没有其他用途。 我将不会应用数据访问的常规规则并使类数据“受保护”或“私有”。 因此,我们可以从以下开始:

class SnowData {

     public $title;
     public $description;
     public $pubDate;

     // Constructor
     //
     function __construct( $t, $d, $p ) {
          $this->title = $t;
          $this->description = $d;
          $this->pubDate = $p;
     }

}

The constructor simply allows me to create the object with all 3 pieces of data in one statement. However the date is in an "awkward" format and it would suit me better if it was in a simpler format. Therefore I'll use the constructor to feed the date into strtotime()

构造函数只允许我在一条语句中创建包含所有3个数据的对象。 但是,日期采用“笨拙”的格式,如果采用更简单的格式,则更适合我。 因此,我将使用构造函数将日期输入到strtotime()

class SnowData {

     public $title;
     public $description;
     public $pubDate;

     // Constructor
     //
     function __construct( $t, $d, $p ) {
          $this->title = $t;
          $this->description = $d;
          $this->pubDate = strtotime($p);
     }

}

From the XML it is also obvious that getting the depth out will be a pain so I will add a small member function to the class to allow me to use a RegEx to pull the data

从XML显而易见,深入研究会很痛苦,因此我将向类添加一个小的成员函数,以允许我使用RegEx提取数据。

class SnowData {

     public $title;
     public $description;
     public $pubDate;

     // Constructor
     //
     function __construct( $t, $d, $p ) {
          $this->title = $t;
          $this->description = $d;
          $this->pubDate = strtotime($p);
     }
    
     // Pull the base depth using a regex
     //
     function getDepth() {
          preg_match('~^.*Base Depth:\s+([0-9]+)\s+cm\s*$~', $this->description, $matches );
          return $matches[1];
     }

}

收集资料 (Collecting the data)

So we are now ready to go. We have somewhere that stores and formats the data and makes it easy to use. Now all we need to do is collect it. We will use the simpleXML object to collect the data and then we will break each entry down and store it as an array of SnowData objects

现在我们准备出发了。 我们在某个地方可以存储和格式化数据,并使其易于使用。 现在,我们需要做的就是收集它。 我们将使用simpleXML对象收集数据,然后将每个条目分解并将其存储为SnowData对象的数组

     // Load the XML
     //
     $xml = simplexml_load_file("http://......rss");


     // Array to collect the data
     //
     $arr = array();


     // Process the XML
     //
     foreach( $xml->channel->item as $anEntry ) {
          $arr [] = new SnowData(
                                   (string) $anEntry->title,
                                   (string) $anEntry->description,
                                   (string) $anEntry->pubDate
                                );
     }

Now we have an array of SnowData objects which we want to sort into descending depth of snow, since our skiers will want the deepest stuff. We can use PHP's uasort with a custom sort routine like so

现在我们有了一个SnowData对象数组,我们希望将它们分类为降雪深度,因为我们的滑雪者将需要最深的东西。 我们可以将PHP的uasort与这样的自定义排序例程一起使用

     // A custom sort based on snow depth
     //
     function snowDepthSort( $a, $b ) {

          $aDepth = $a->getDepth();
          $bDepth = $b->getDepth();

          if ( $aDepth < $bDepth )
               return 1;
          else
               if ( $aDepth > $bDepth )
                    return -1;

          return 0;                    
     }

Note how simple it is to get the depth. The class is doing all the hard work here. Now all we want is the best 10 results so we use array_slice to get the top 10

请注意获取深度有多简单。 全班在这里都在努力。 现在我们想要的是最好的10个结果,所以我们使用array_slice获得前10个结果

     $arr = array_slice( $arr, 0, 10 );

$ arr = array_slice($ arr,0,10);

And we are done. We now have an array of the top 10 depths all ready for output

我们完成了。 现在,我们准备了前十个深度的数组,准备输出

     // Produce a table
     //
     $tab = "<table>\n";

     foreach( $arr as $aSnowObj ) {
          $tab .= "<tr>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->title . "(" . date("d/m/Y H:i", $aSnowObj->pubDate) . ")";
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->getDepth();
          $tab .=    "</td>\n";
          $tab .= "</tr>\n";
          
     }
     
     $tab .= "</table>\n";

     echo $tab;
     

扩展代码以处理更多数据 (Extending the code to handle more data)

Let us now extend the class to add a simple text description, the location or country code. All we need to do is extend the class to have a location field and extend the constructor to have an extra parameter.

现在,让我们扩展类以添加简单的文本描述,位置或国家/地区代码。 我们需要做的就是扩展类以具有位置字段,并扩展构造函数以具有额外的参数。

class SnowData {

     public $location;
     public $title;
     public $description;
     public $pubDate;

     // Constructor
     //
     function __construct( $l, $t, $d, $p ) {
          $this->location = $l;
          $this->title = $t;
          $this->description = $d;
          $this->pubDate = strtotime($p);
     }
    
     // Pull the base depth using a regex
     //
     function getDepth() {
          preg_match('~^.*Base Depth:\s+([0-9]+)\s+cm\s*$~', $this->description, $matches );
          return $matches[1];
     }

}

We then update the collection loop

然后,我们更新收集循环

     
     // Process the XML
     //
     foreach( $xml->channel->item as $anEntry ) {
          $arr [] = new SnowData(
                                   "France",
                                   (string) $anEntry->title,
                                   (string) $anEntry->description,
                                   (string) $anEntry->pubDate
                                );
     }

and then amend the output table

然后修改输出表

     // Produce a table
     //
     $tab = "<table border='1'>\n";

     foreach( $arr as $aSnowObj ) {
          $tab .= "<tr>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->location;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->title . "(" . date("d/m/Y H:i", $aSnowObj->pubDate) . ")";
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->getDepth();
          $tab .=    "</td>\n";
          $tab .= "</tr>\n";
          
     }
     
     $tab .= "</table>\n";

     echo $tab;

How simple was that?

那有多简单?

从多个提要中收集 (Collecting from multiple feeds)

Let us now go for a more substantial alteration. To collect the data from THREE separate RSS feeds and select only the top ten results. To achieve this all we need to do is to make the collection process a function that accepts a result array BY REFERENCE so that we can pass the alterations straight back out again. We get this:

现在让我们进行更实质性的修改。 要从三个单独的RSS提要中收集数据并仅选择前十个结果。 为此,我们需要做的就是使收集过程成为一个函数,该函数可以通过REFERENCE接受结果数组,以便我们可以再次将更改直接传递回去。 我们得到这个:

     function collectRSS( $location, $feedUrl, & $arr ) {
     
          // Load the XML
          //
          $xml = simplexml_load_file( $feedUrl );

          // Process the XML
          //
          foreach( $xml->channel->item as $anEntry ) {
               $arr [] = new SnowData(
                                        $location,
                                        (string) $anEntry->title,
                                        (string) $anEntry->description,
                                        (string) $anEntry->pubDate
                                   );
          }


     }

which we can call like this

我们可以这样称呼

     $arr = array();

     collectRSS( "Austria", "http://www.....rss",  $arr );
     collectRSS( "Austria", "http://www........rss", $arr );
     collectRSS( "France", "http://www....rss",  $arr );

And nothing else need change. Our final code looks like

而且没有其他需要改变的地方。 我们的最终代码如下所示

class SnowData {

     public $location;
     public $title;
     public $description;
     public $pubDate;

     // Constructor
     //
     function __construct( $l, $t, $d, $p ) {
          $this->location = $l;
          $this->title = $t;
          $this->description = $d;
          $this->pubDate = strtotime($p);
     }
    
     // Pull the base depth using a regex
     //
     function getDepth() {
          preg_match('~^.*Base Depth:\s+([0-9]+)\s+cm\s*$~', $this->description, $matches );
          return $matches[1];
     }

}

     


     // A custom sort based on snow depth
     //
     function snowDepthSort( $a, $b ) {

          $aDepth = $a->getDepth();
          $bDepth = $b->getDepth();

          if ( $aDepth < $bDepth )
               return 1;
          else
               if ( $aDepth > $bDepth )
                    return -1;

          return 0;                    
     }






     function collectRSS( $location, $feedUrl, & $arr ) {
     
          // Load the XML
          //
          $xml = simplexml_load_file( $feedUrl );

          // Process the XML
          //
          foreach( $xml->channel->item as $anEntry ) {
               $arr [] = new SnowData(
                                        $location,
                                        (string) $anEntry->title,
                                        (string) $anEntry->description,
                                        (string) $anEntry->pubDate
                                   );
          }


     }


    
     

     // Array to collect the data
     //
     $arr = array();


     // Collect all the data
     //
     collectRSS( "Austria", "http://www......rss",  $arr );
     collectRSS( "Italy", "http://www.....snow.rss", $arr );
     collectRSS( "France", "http://www....snow.rss",  $arr );



     // Sort the array into descending snowdepth
     //
     uasort( $arr, 'snowDepthSort' );
     $arr = array_slice( $arr, 0, 10);


     // Produce a table
     //
     $tab = "<table border='1'>\n";

     foreach( $arr as $index => $aSnowObj ) {

          $tab .= "<tr>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->location;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->title . "(" . date("d/m/Y H:i", $aSnowObj->pubDate) . ")";
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->getDepth();
          $tab .=    "</td>\n";
          $tab .= "</tr>\n";
     }
     
     $tab .= "</table>\n";

     echo $tab;

摘要 (Summary)

By grouping the data items into a PHP class, we make the maintenance and addition of further data items a trivial matter. We can even add methods to the class to tease out difficult data, but the real purpose of the class is to GROUP data to make parameter passing trivial.

通过将数据项分组到一个PHP类中,我们使维护和添加其他数据项变得无关紧要。 我们甚至可以在类中添加方法来挑逗困难的数据,但是类的真正目的是对GROUP数据进行简单的参数传递。

By combining the class object with an array we can build up a list of data for further processing simply by passing into functions by reference. This allows us to construct functions which are completely focused on one task which results in simpler, more reliable code. Passing the array by reference also minimizes data copying and memory utilization as well. A final benefit is that the collection , processing and presentation can be split into completely independent tasks reducing interdependence between sections of code.

通过将类对象与数组结合在一起,我们可以简单地通过引用传递给函数来建立数据列表以进行进一步处理。 这使我们能够构建完全专注于一项任务的功能,从而产生更简单,更可靠的代码。 通过引用传递数组还可以最大程度地减少数据复制和内存利用率。 最后的好处是,可以将收集,处理和表示分成完全独立的任务,从而减少代码部分之间的相互依赖性。

To collect new data items we need merely extend the class, the collection loop and what we show in the output table. No other parameters or control-flow control needs changing. If we wanted a different sort we could simply change the sort function. All the main functions are clear and are isolated from each other. Changing one presents a minimal impact on the others.

要收集新的数据项,我们只需要扩展类,收集循环以及在输出表中显示的内容即可。 无需更改其他参数或控制流控制。 如果我们想要一个不同的排序,我们可以简单地更改排序功能。 所有主要功能都清晰且相互隔离。 改变一个对他人的影响很小。

I have found this overall structure of an array of data objects, very flexible in use and very quick at producing reliable results. It encourages clear thinking at design time and although people may be put off by the apparent extra work ("You mean I have to code up a whole class? No way....") the benefits soon become apparent. This programming model is both flexible and straightforward.

我发现了数据对象数组的整体结构,使用非常灵活,产​​生可靠结果的速度非常快。 它鼓励在设计时进行清晰的思考,尽管人们可能会因表面上的额外工作而被推迟(“您的意思是我必须编写整个课程?否则……。”),这些好处很快就会显现出来。 这种编程模型既灵活又直接。

致谢 (Acknowledgments)

My thanks to maccaj51 for allowing me to use the questions below as a basis for this article. The original questions are

感谢maccaj51,它允许我使用以下问题作为本文的基础。 原来的问题是

https://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_26232550.html https://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_26232550.html https://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_26235708.html https://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_26235708.html

翻译自: https://www.experts-exchange.com/articles/3212/Using-PHP-classes-to-group-data-in-memory.html

php数据分组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值