chilimatic/framework

chilimatic 框架,激发好奇心

dev-master 2016-05-04 07:54 UTC

This package is auto-updated.

Last update: 2024-09-09 13:14:13 UTC


README

Build Status

chilimatic-framework

这只是为了反馈 :) 如果觉得有用,请fork它,使用它,如果有好的想法,请告诉我

#前言

在有些地方,我故意违反了最佳实践,这是基于PHP解释器的结构。这些决定自然可以争论。在开始讨厌之前,这里有一个例子。

节点获取器和设置器。它们仍然存在,但所有属性都是公共的,这与在phpng之前的行为有关 http://jpauli.github.io/2015/01/22/on-php-function-calls.html。我需要用新引擎对其进行基准测试,因为它们已经改变了函数调用的行为,所以它们具有更少的开销和更好的性能。

https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view

我非常乐观,我可以用它们再次。但如果你使用数百个节点,结构会比使用公共访问方法调用慢。因此,图结构应该是一个私有属性,但图内部的一切都是公共的。

同样的情况也适用于数组。在PHP7之前,我不会推荐使用超过1000个节点 -> 看数组的内存分配 https://nikic.github.io/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html

但如https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view所述,你可以看到他们已经改变了PHP数组的结构 [从PDF中复制]

  • 散列表大小从72字节减少到56字节
  • 桶大小从72字节减少到32字节
  • 所有桶的内存一次性分配
  • Bucket.key现在是指向zend_string的指针,它不需要被复制(只需增加引用计数器即可)
  • 数组元素的值嵌入到桶中
  • 改进了数据局部性 => 减少了CPU缓存未命中

这意味着

$a = array();
for ($i = 0; $i < 1000000; $i++) $a[$i] = array("hello");
echo memory_get_usage(true);

内存使用量 428 MB [旧] 33 MB [新] 时间 0.49 秒[旧] 0.06 秒 [新]

这很重要,因为内存总是有问题,尤其是因为unset() 使用垃圾回收器。如果你比较大量数据,你不能使用unset,因为GC不会立即收集它,而是“当他觉得最好”时,这意味着你会耗尽内存,所以你需要将值置为null以立即释放一些内存 .....

配置

这是一个基于域的配置系统

  • *.cfg
  • *.example.com.cfg
  • subdomain.example.com.cfg

这里的 *.cfg 是根配置,它将是第一个被 *.example.com 覆盖的设置,它将被 subdomain.example.com.cfg 覆盖

例如

   use \chilimatic\lib\config\Config;
   Config::getInstance(
   [
      'type' => 'File',
      <path/to/folder/withconfigfiles>
   ]
   );

*.cfg的内容

   # page settings
   default_timezone = 'Europe/Vienna'
   default_page_encoding = 'utf-8'

   #cache settings
   cache_type = 'memcached'
   cache_settings = { "server_list" : [{"host" : "127.0.0.1", "port" : "11211", "weight" : 1 }] }

   #Session data
   session_type = "Cache"
   session_cache = 'Memcached'

*.example.com的内容

session_type = "Mysql"

所以如果你在example.com域名上使用

Config::get('session_type'); // returns Mysql
Config::get('cache_settings') // return \stdClass containing the json 

这是一个如何使用配置对象的简单示例

对于单例来说,这是一个反模式! :) 在这种情况下,单例只是一个包装任何配置的容器

use \chilimatic\lib\config\File as Config;
$config = new Config([\chilimatic\lib\config\File::CONFIG_PATH_INDEX => <path/to/folder/withconfigfiles>]);

或者工厂

use \chilimatic\lib\config\ConfigFactory;
$config = ConfigFactory::make('File',[\chilimatic\lib\config\File::CONFIG_PATH_INDEX => <path/to/folder/withconfigfiles>] );

数组是一个接口问题,因为ini可以接受多个参数,如果它们在PHP7中确认了这个,我会只为PHP7实现它 https://wiki.php.net/rfc/named_params

DI

让我们考虑一下服务收集,默认服务收集可以在

lib/general/config/default-service-collection.php

这只是一个示例。我采用了闭包方法,这样更容易添加一个服务作为示例。

    $dispatcher = \chilimatic\lib\di\ClosureFactory::getInstance(
        realpath('<path to your closure collection>');
    );
    // set a db object
    $dispatcher->set('db', function() use ($dispatcher) {
        $config = $dispatcher->get('config');

        $mysqlStorage = new \chilimatic\lib\database\mysql\MysqlConnectionStorage();
        $mysqlStorage->addConnection(
            $config->get('mysql_db_host'),
            $config->get('mysql_db_user'),
            $config->get('mysql_db_password'),
            $config->get('mysql_db_name'),
            null
        );

        return $mysqlStorage;
    });
   
    $dispatcher->set('entity-manager', function() use ($dispatcher) {
        $mysqlStorage = $dispatcher->get('db');
        $master = $mysqlStorage->getConnection(0);
        $queryBuilder = $dispatcher->get('query-builder', ['db' => new \chilimatic\lib\database\mysql\Mysql($master)]);

        $em = new \chilimatic\lib\database\orm\EntityManager(
            new \chilimatic\lib\database\mysql\Mysql($master),
            $queryBuilder
        );
        return $em;
    });


    // get a new instance 
    $dispatcher->get('db', []);
    // get it as "singelton"
    $dispatcher->get('em', [], true);

但是让我们从一个基本的应用程序示例开始,这样您可以尝试一下。您创建“基本”结构

<path>
 - app
   - config
     - *.cfg
     - *.example.com.cfg
     - www.example.com.cfg
   - module
     - main [default]
       - controller
         - Index.php
       - view
         - index.phtml
 - public [Docroot]
   - index.php
 - vendor/chilimatic/framework/lib [framework]

public/index.php的内容

<?php

require_once '../vendor/autoload.php';

define('APPLICATION_PATH', realpath('../'));

try {
    use chilimatic\lib\config\Config;

    date_default_timezone_set('Europe/Vienna');
    define('INCLUDE_ROOT', '/var/www/chilimatic.com' );

    set_exception_handler(function($e)
    {
        echo $e->getMessage();
        echo $e->getTraceAsString();
    });
    
    $dispatcher = \chilimatic\lib\di\ClosureFactory::getInstance(
        realpath('../app/config/serviceCollection.php')
    );

    /**
     * Create the config
     */
    $config = $dispatcher->get('config', [
        'type' => 'File',
        \chilimatic\lib\config\File::CONFIG_PATH_INDEX => INCLUDE_ROOT . '/app/config/'
    ]);

    /**
     * Set default timezone based on the config
     */
    date_default_timezone_set((string) $config->get('default_timezone'));

    if (!$config->get((string) 'document_root')) {
        $config->set((string) 'document_root', (string) INCLUDE_ROOT);
    }

    $config->set('app_root', (string) $config->get('document_root') . (string) "/app");
    $config->set('lib_root', (string) $config->get('document_root') . (string) $config->get('lib_dir' ));
    
    $application = new \chilimatic\lib\application\HTTPMVC($dispatcher, $dispatcher->get('config'));
    // this is step so people can inject
    $application->init();
    // returns the rendered result
    echo $application->getHandler()->getContent();
}
catch (Exception $e)
{
    // show error trace
    if (isset($dispatcher) && $dispatcher->get('error-handler', null, true)->getClient()->showError()) {
        $dispatcher->get('error-handler', null, true)->getClient()->log($e->getMessage(), $e->getTraceAsString())->send();
    } else {
        echo 'nothing to concern you with :)';
    }

app/module/main/controller/Index.php的内容

namespace chilimatic\app\module\main\controller;

/**
 * Class Index
 * @package \chilimatic\app\default\controller
 */
class Index
{
    /**
     * Class Index
     * @view \chilimatic\lib\view\PHtml()
     */
    public function indexAction(){
        $this->view->pageTitle = 'myPage';
    }
}

app/module/main/view/index.phtml的内容

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title><?php echo $this->pageTitle; ?></title>
</head>
<body></body>
</html>

数据结构

普通的“节点”

$node = new \chilimatic\lib\datastructure\graph\Node(null, '.', '');
$node->addChild(new \chilimatic\lib\datastructure\graph\Node($node, 'test', 23));
$node->getChildren(); // return [\chilimatic\lib\datastructure\graph\Node($node, 'test', 23)]
$node->getLastByKey("test"); // return \chilimatic\lib\datastructure\graph\Node($node, 'test', 23)
$node->getLastByKey("test")->getData(); // return 23

二叉树

$bt = \chilimatic\lib\datastructure\graph\tree\binary\BinaryTree();
$bt->insert(\chilimatic\lib\datastructure\graph\tree\binary\BinaryNode('key', [1,2,3]));
$bt->insert(\chilimatic\lib\datastructure\graph\tree\binary\BinaryNode('key1', [1,2,3]));

$bt->findByKey('key1'); // returns \chilimatic\lib\datastructure\graph\tree\binary\BinaryNode('key1', [1,2,3])

会话

您可以轻松实现自己的会话存储系统

// uses memcached as session storage
$session = new chilimatic\lib\session\handler\Session(
                chilimatic\lib\session\engine\Factory::make('Cache', ['type' => 'memcached'])
            );
$session->set('value', 'data');
$session->get('value'); // returns data

路由

可能的类型包括

  • stdclass
  • 数组(数字索引)
  • 数组(关联索引)
  • lambda函数
  • 函数调用
  • 静态内容

路由存储在二叉树中,因此我希望它的性能很好,您始终可以回退到常见的路由

 \chilimatic\route\Router::register('/test/(:num)', array('job', 'load'), '/');
 \chilimatic\route\Router::register('/user/add/(:num)', array('object' => 'user', 'method' => 'add', 'namespace' => '\\user\\', 'param' => array(true, false)));
 \chilimatic\route\Route::register('/test/(:char)', array('object' => 'user', 'method' => 'add', 'namespace' => '\\user\\', 'param' => array(true, false)));
\chilimatic\route\Route::register('/mytest/(:array)[|]',  function($num) { foreach($num as $val) {  echo $val . ': this is a test'; }});

缓存

$cache = \chilimatic\lib\cache\engine\CacheFactory::make('memcached', []);
// this will get you a memcached I added a listing for memcached so you can actually see 
$cache->set('myData', [], $ttl = 10)
$cache->listCache(); // returns ['myData', {'data'}]
$cache->delete('myData'); // returns true
$cache->listCache(); // returns []

##ORM / 数据库

// you can have multiple connections in the storage -> if you just want to use pdo / mysqli
$mysqlStorage = new \chilimatic\lib\database\mysql\MysqlConnectionStorage();
$mysqlStorage->addConnection('localhost','username', 'password', 'database';
$master = $mysqlStorage->getConnection(0);

// the entity manager
$em = new \chilimatic\lib\database\orm\EntityManager(new \chilimatic\lib\database\mysql\Mysql($master));
// the entityManager needs the corret QueryBuilder -> atm there is only MySQL supportet
$queryBuilder = new \chilimatic\lib\database\orm\querybuilder\MysqlQueryBuilder();
$queryBuilder->setCache(\chilimatic\lib\di\ClosureFactory::getInstance()->get('cache', ['type' => 'shmop']));
$em->setQueryBuilder($queryBuilder);


/**
 * Class Model
 *
 * @package \app\model
 */
class Model1 extends AbstractModel {

    /**
     * @var int
     */
    protected $id;

    /**
     * @var int
     */
    protected $model2_id;

    /**
     * maps it to the model2 id and adds the model here
     * @ORM model2_id = \Model2;
     */
    protected $model2;

    /**
     * @param int $id
     */
    public function setModel1($id) {
        $this->model1 = (int) $id;
    }

    /**
     * @param int $id
     */
    public function setModel2($id) {
        $this->model2 = (int) $id;
    }

    /**
     * @return array
     */
    public function jsonSerialize() {
        return [
          'id' => $id,
          'model2_id' => $model2_id
        ];
    }
}

/**
 * Class Model2
 * @ORM table=database.anyTable;
 */
class Model2 extends AbstractModel {
    /**
     * @var int
     */
    protected $id;
}
// returns the model
$model1 = $em->findOneBy(new Model1(), [
    'id' => 1
]);

$model1->setModel2(3);
$em->persist($model1); // updates the model


// create a new entry
$newModel = new Model1();
$newModel->setModel1(2);
$newModel->setModel2(3);

// creates a new table entry
$em->persist($newModel);  

整个框架主要是学术性的,但如果您发现一个不错的应用程序想要使用它,或者您只是想看看一些概念或给我一些有用的反馈,我将非常高兴。

节点过滤器

这是我从Doctrine采取的方法。这是一个基本的过滤器系统。

$filterFactory = new \chilimatic\lib\datastructure\graph\filter\Factory();
// the validator checks if the name is conform to the convetions this-will-be
$filterFactory->setValidator(new chilimatic\lib\validator\DynamicCallNamePreTransformed());
// the transformer will change the this-will-be string to ThisWillBe
$filterFactory->setTransformer(new chilimatic\lib\transformer\string\DynamicObjectCallName());
$filterLastNode = $filterFactory->make('lastNode');
$filterFirstNode = $filterFactory->make('firstNode');


// so lets create a bunch of nodes
$mainNode = new \chilimatic\lib\datastructure\graph\Node($node, 'test', null);
for ($i = 0; $i < 10; $i++) {
   $mainNode->addChild(new \chilimatic\lib\datastructure\graph\Node($node, 'test', $i))
}

$mainNode->getByKey('test', $filterLastNode); // this should return the node with the value 10
$mainNode->getByKey('test', $filterFirstNode); // this should return the node with the value 0